+static int
+test_ipsec_proto_process(const struct ipsec_test_data td[],
+ struct ipsec_test_data res_d[],
+ int nb_td,
+ bool silent,
+ const struct ipsec_test_flags *flags)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ struct crypto_unittest_params *ut_params = &unittest_params;
+ struct rte_security_capability_idx sec_cap_idx;
+ const struct rte_security_capability *sec_cap;
+ struct rte_security_ipsec_xform ipsec_xform;
+ uint8_t dev_id = ts_params->valid_devs[0];
+ enum rte_security_ipsec_sa_direction dir;
+ struct ipsec_test_data *res_d_tmp = NULL;
+ uint32_t src = RTE_IPV4(192, 168, 1, 0);
+ uint32_t dst = RTE_IPV4(192, 168, 1, 1);
+ int salt_len, i, ret = TEST_SUCCESS;
+ struct rte_security_ctx *ctx;
+ uint8_t *input_text;
+ uint32_t verify;
+
+ ut_params->type = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL;
+ gbl_action_type = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL;
+
+ /* Use first test data to create session */
+
+ /* Copy IPsec xform */
+ memcpy(&ipsec_xform, &td[0].ipsec_xform, sizeof(ipsec_xform));
+
+ dir = ipsec_xform.direction;
+ verify = flags->tunnel_hdr_verify;
+
+ if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) && verify) {
+ if (verify == RTE_SECURITY_IPSEC_TUNNEL_VERIFY_SRC_DST_ADDR)
+ src += 1;
+ else if (verify == RTE_SECURITY_IPSEC_TUNNEL_VERIFY_DST_ADDR)
+ dst += 1;
+ }
+
+ memcpy(&ipsec_xform.tunnel.ipv4.src_ip, &src, sizeof(src));
+ memcpy(&ipsec_xform.tunnel.ipv4.dst_ip, &dst, sizeof(dst));
+
+ ctx = rte_cryptodev_get_sec_ctx(dev_id);
+
+ sec_cap_idx.action = ut_params->type;
+ sec_cap_idx.protocol = RTE_SECURITY_PROTOCOL_IPSEC;
+ sec_cap_idx.ipsec.proto = ipsec_xform.proto;
+ sec_cap_idx.ipsec.mode = ipsec_xform.mode;
+ sec_cap_idx.ipsec.direction = ipsec_xform.direction;
+
+ if (flags->udp_encap)
+ ipsec_xform.options.udp_encap = 1;
+
+ sec_cap = rte_security_capability_get(ctx, &sec_cap_idx);
+ if (sec_cap == NULL)
+ return TEST_SKIPPED;
+
+ /* Copy cipher session parameters */
+ if (td[0].aead) {
+ memcpy(&ut_params->aead_xform, &td[0].xform.aead,
+ sizeof(ut_params->aead_xform));
+ ut_params->aead_xform.aead.key.data = td[0].key.data;
+ ut_params->aead_xform.aead.iv.offset = IV_OFFSET;
+
+ /* Verify crypto capabilities */
+ if (test_ipsec_crypto_caps_aead_verify(
+ sec_cap,
+ &ut_params->aead_xform) != 0) {
+ if (!silent)
+ RTE_LOG(INFO, USER1,
+ "Crypto capabilities not supported\n");
+ return TEST_SKIPPED;
+ }
+ } else {
+ /* Only AEAD supported now */
+ return TEST_SKIPPED;
+ }
+
+ if (test_ipsec_sec_caps_verify(&ipsec_xform, sec_cap, silent) != 0)
+ return TEST_SKIPPED;
+
+ salt_len = RTE_MIN(sizeof(ipsec_xform.salt), td[0].salt.len);
+ memcpy(&ipsec_xform.salt, td[0].salt.data, salt_len);
+
+ struct rte_security_session_conf sess_conf = {
+ .action_type = ut_params->type,
+ .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+ .ipsec = ipsec_xform,
+ .crypto_xform = &ut_params->aead_xform,
+ };
+
+ /* Create security session */
+ ut_params->sec_session = rte_security_session_create(ctx, &sess_conf,
+ ts_params->session_mpool,
+ ts_params->session_priv_mpool);
+
+ if (ut_params->sec_session == NULL)
+ return TEST_SKIPPED;
+
+ for (i = 0; i < nb_td; i++) {
+ /* Setup source mbuf payload */
+ ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool);
+ memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0,
+ rte_pktmbuf_tailroom(ut_params->ibuf));
+
+ input_text = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf,
+ td[i].input_text.len);
+
+ memcpy(input_text, td[i].input_text.data,
+ td[i].input_text.len);
+
+ /* Generate crypto op data structure */
+ ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool,
+ RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+ if (!ut_params->op) {
+ printf("TestCase %s line %d: %s\n",
+ __func__, __LINE__,
+ "failed to allocate crypto op");
+ ret = TEST_FAILED;
+ goto crypto_op_free;
+ }
+
+ /* Attach session to operation */
+ rte_security_attach_session(ut_params->op,
+ ut_params->sec_session);
+
+ /* Set crypto operation mbufs */
+ ut_params->op->sym->m_src = ut_params->ibuf;
+ ut_params->op->sym->m_dst = NULL;
+
+ /* Copy IV in crypto operation when IV generation is disabled */
+ if (dir == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
+ ipsec_xform.options.iv_gen_disable == 1) {
+ uint8_t *iv = rte_crypto_op_ctod_offset(ut_params->op,
+ uint8_t *,
+ IV_OFFSET);
+ int len;
+
+ if (td[i].aead)
+ len = td[i].xform.aead.aead.iv.length;
+ else
+ len = td[i].xform.chain.cipher.cipher.iv.length;
+
+ memcpy(iv, td[i].iv.data, len);
+ }
+
+ /* Process crypto operation */
+ process_crypto_request(dev_id, ut_params->op);
+
+ ret = test_ipsec_status_check(ut_params->op, flags, dir, i + 1);
+ if (ret != TEST_SUCCESS)
+ goto crypto_op_free;
+
+ if (res_d != NULL)
+ res_d_tmp = &res_d[i];
+
+ ret = test_ipsec_post_process(ut_params->ibuf, &td[i],
+ res_d_tmp, silent, flags);
+ if (ret != TEST_SUCCESS)
+ goto crypto_op_free;
+
+ rte_crypto_op_free(ut_params->op);
+ ut_params->op = NULL;
+
+ rte_pktmbuf_free(ut_params->ibuf);
+ ut_params->ibuf = NULL;
+ }
+
+crypto_op_free:
+ rte_crypto_op_free(ut_params->op);
+ ut_params->op = NULL;
+
+ rte_pktmbuf_free(ut_params->ibuf);
+ ut_params->ibuf = NULL;
+
+ if (ut_params->sec_session)
+ rte_security_session_destroy(ctx, ut_params->sec_session);
+ ut_params->sec_session = NULL;
+
+ return ret;
+}
+
+static int
+test_ipsec_proto_known_vec(const void *test_data)
+{
+ struct ipsec_test_data td_outb;
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ memcpy(&td_outb, test_data, sizeof(td_outb));
+
+ /* Disable IV gen to be able to test with known vectors */
+ td_outb.ipsec_xform.options.iv_gen_disable = 1;
+
+ return test_ipsec_proto_process(&td_outb, NULL, 1, false, &flags);
+}
+
+static int
+test_ipsec_proto_known_vec_inb(const void *td_outb)
+{
+ struct ipsec_test_flags flags;
+ struct ipsec_test_data td_inb;
+
+ memset(&flags, 0, sizeof(flags));
+
+ test_ipsec_td_in_from_out(td_outb, &td_inb);
+
+ return test_ipsec_proto_process(&td_inb, NULL, 1, false, &flags);
+}
+
+static int
+test_ipsec_proto_all(const struct ipsec_test_flags *flags)
+{
+ struct ipsec_test_data td_outb[IPSEC_TEST_PACKETS_MAX];
+ struct ipsec_test_data td_inb[IPSEC_TEST_PACKETS_MAX];
+ unsigned int i, nb_pkts = 1, pass_cnt = 0;
+ int ret;
+
+ if (flags->iv_gen ||
+ flags->sa_expiry_pkts_soft ||
+ flags->sa_expiry_pkts_hard)
+ nb_pkts = IPSEC_TEST_PACKETS_MAX;
+
+ for (i = 0; i < RTE_DIM(aead_list); i++) {
+ test_ipsec_td_prepare(&aead_list[i],
+ NULL,
+ flags,
+ td_outb,
+ nb_pkts);
+
+ ret = test_ipsec_proto_process(td_outb, td_inb, nb_pkts, true,
+ flags);
+ if (ret == TEST_SKIPPED)
+ continue;
+
+ if (ret == TEST_FAILED)
+ return TEST_FAILED;
+
+ test_ipsec_td_update(td_inb, td_outb, nb_pkts, flags);
+
+ ret = test_ipsec_proto_process(td_inb, NULL, nb_pkts, true,
+ flags);
+ if (ret == TEST_SKIPPED)
+ continue;
+
+ if (ret == TEST_FAILED)
+ return TEST_FAILED;
+
+ if (flags->display_alg)
+ test_ipsec_display_alg(&aead_list[i], NULL);
+
+ pass_cnt++;
+ }
+
+ if (pass_cnt > 0)
+ return TEST_SUCCESS;
+ else
+ return TEST_SKIPPED;
+}
+
+static int
+test_ipsec_proto_display_list(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.display_alg = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_iv_gen(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.iv_gen = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_sa_exp_pkts_soft(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.sa_expiry_pkts_soft = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_sa_exp_pkts_hard(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.sa_expiry_pkts_hard = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_err_icv_corrupt(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.icv_corrupt = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_udp_encap(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.udp_encap = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_tunnel_src_dst_addr_verify(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.tunnel_hdr_verify = RTE_SECURITY_IPSEC_TUNNEL_VERIFY_SRC_DST_ADDR;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_tunnel_dst_addr_verify(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.tunnel_hdr_verify = RTE_SECURITY_IPSEC_TUNNEL_VERIFY_DST_ADDR;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_udp_ports_verify(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.udp_encap = true;
+ flags.udp_ports_verify = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_inner_ip_csum(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.ip_csum = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+
+static int
+test_ipsec_proto_inner_l4_csum(const void *data __rte_unused)
+{
+ struct ipsec_test_flags flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ flags.l4_csum = true;
+
+ return test_ipsec_proto_all(&flags);
+}
+