X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest%2Ftest_cryptodev_security_ipsec.c;h=bcd9746c98895ed1db20f7eb52aba3160ab3d1cd;hb=88caad251c8de3a84e353b0b2a27014bc303df87;hp=aebbe66639dfc5a47f8b6240921638cc3f95e74c;hpb=0f4531903acb42d894ff5bd4373a222400837315;p=dpdk.git diff --git a/app/test/test_cryptodev_security_ipsec.c b/app/test/test_cryptodev_security_ipsec.c index aebbe66639..bcd9746c98 100644 --- a/app/test/test_cryptodev_security_ipsec.c +++ b/app/test/test_cryptodev_security_ipsec.c @@ -4,12 +4,17 @@ #include #include +#include #include #include +#include +#include #include "test.h" #include "test_cryptodev_security_ipsec.h" +#define IV_LEN_MAX 16 + extern struct ipsec_test_data pkt_aes_256_gcm; int @@ -32,6 +37,14 @@ test_ipsec_sec_caps_verify(struct rte_security_ipsec_xform *ipsec_xform, return -ENOTSUP; } + if (ipsec_xform->options.udp_ports_verify == 1 && + sec_cap->ipsec.options.udp_ports_verify == 0) { + if (!silent) + RTE_LOG(INFO, USER1, "UDP encapsulation ports " + "verification is not supported\n"); + return -ENOTSUP; + } + if (ipsec_xform->options.copy_dscp == 1 && sec_cap->ipsec.options.copy_dscp == 0) { if (!silent) @@ -73,6 +86,40 @@ test_ipsec_sec_caps_verify(struct rte_security_ipsec_xform *ipsec_xform, return -ENOTSUP; } + if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) && + (ipsec_xform->options.iv_gen_disable == 1) && + (sec_cap->ipsec.options.iv_gen_disable != 1)) { + if (!silent) + RTE_LOG(INFO, USER1, + "Application provided IV is not supported\n"); + return -ENOTSUP; + } + + if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) && + (ipsec_xform->options.tunnel_hdr_verify > + sec_cap->ipsec.options.tunnel_hdr_verify)) { + if (!silent) + RTE_LOG(INFO, USER1, + "Tunnel header verify is not supported\n"); + return -ENOTSUP; + } + + if (ipsec_xform->options.ip_csum_enable == 1 && + sec_cap->ipsec.options.ip_csum_enable == 0) { + if (!silent) + RTE_LOG(INFO, USER1, + "Inner IP checksum is not supported\n"); + return -ENOTSUP; + } + + if (ipsec_xform->options.l4_csum_enable == 1 && + sec_cap->ipsec.options.l4_csum_enable == 0) { + if (!silent) + RTE_LOG(INFO, USER1, + "Inner L4 checksum is not supported\n"); + return -ENOTSUP; + } + return 0; } @@ -130,6 +177,56 @@ test_ipsec_td_in_from_out(const struct ipsec_test_data *td_out, } } +static bool +is_ipv4(void *ip) +{ + struct rte_ipv4_hdr *ipv4 = ip; + uint8_t ip_ver; + + ip_ver = (ipv4->version_ihl & 0xf0) >> RTE_IPV4_IHL_MULTIPLIER; + if (ip_ver == IPVERSION) + return true; + else + return false; +} + +static void +test_ipsec_csum_init(void *ip, bool l3, bool l4) +{ + struct rte_ipv4_hdr *ipv4; + struct rte_tcp_hdr *tcp; + struct rte_udp_hdr *udp; + uint8_t next_proto; + uint8_t size; + + if (is_ipv4(ip)) { + ipv4 = ip; + size = sizeof(struct rte_ipv4_hdr); + next_proto = ipv4->next_proto_id; + + if (l3) + ipv4->hdr_checksum = 0; + } else { + size = sizeof(struct rte_ipv6_hdr); + next_proto = ((struct rte_ipv6_hdr *)ip)->proto; + } + + if (l4) { + switch (next_proto) { + case IPPROTO_TCP: + tcp = (struct rte_tcp_hdr *)RTE_PTR_ADD(ip, size); + tcp->cksum = 0; + break; + case IPPROTO_UDP: + udp = (struct rte_udp_hdr *)RTE_PTR_ADD(ip, size); + udp->dgram_cksum = 0; + break; + default: + return; + } + } +} + void test_ipsec_td_prepare(const struct crypto_param *param1, const struct crypto_param *param2, @@ -157,9 +254,26 @@ test_ipsec_td_prepare(const struct crypto_param *param1, td->xform.aead.aead.algo = param1->alg.aead; td->xform.aead.aead.key.length = param1->key_length; + + if (flags->iv_gen) + td->ipsec_xform.options.iv_gen_disable = 0; + + if (flags->sa_expiry_pkts_soft) + td->ipsec_xform.life.packets_soft_limit = + IPSEC_TEST_PACKETS_MAX - 1; + + if (flags->ip_csum) { + td->ipsec_xform.options.ip_csum_enable = 1; + test_ipsec_csum_init(&td->input_text.data, true, false); + } + + if (flags->l4_csum) { + td->ipsec_xform.options.l4_csum_enable = 1; + test_ipsec_csum_init(&td->input_text.data, false, true); + } + } - RTE_SET_USED(flags); RTE_SET_USED(param2); } @@ -180,6 +294,28 @@ test_ipsec_td_update(struct ipsec_test_data td_inb[], int icv_pos = td_inb[i].input_text.len - 4; td_inb[i].input_text.data[icv_pos] += 1; } + + if (flags->sa_expiry_pkts_hard) + td_inb[i].ipsec_xform.life.packets_hard_limit = + IPSEC_TEST_PACKETS_MAX - 1; + + if (flags->udp_encap) + td_inb[i].ipsec_xform.options.udp_encap = 1; + + if (flags->udp_ports_verify) + td_inb[i].ipsec_xform.options.udp_ports_verify = 1; + + td_inb[i].ipsec_xform.options.tunnel_hdr_verify = + flags->tunnel_hdr_verify; + + if (flags->ip_csum) + td_inb[i].ipsec_xform.options.ip_csum_enable = 1; + + if (flags->l4_csum) + td_inb[i].ipsec_xform.options.l4_csum_enable = 1; + + /* Clear outbound specific flags */ + td_inb[i].ipsec_xform.options.iv_gen_disable = 0; } } @@ -213,18 +349,168 @@ test_ipsec_tunnel_hdr_len_get(const struct ipsec_test_data *td) return len; } +static int +test_ipsec_iv_verify_push(struct rte_mbuf *m, const struct ipsec_test_data *td) +{ + static uint8_t iv_queue[IV_LEN_MAX * IPSEC_TEST_PACKETS_MAX]; + uint8_t *iv_tmp, *output_text = rte_pktmbuf_mtod(m, uint8_t *); + int i, iv_pos, iv_len; + static int index; + + if (td->aead) + iv_len = td->xform.aead.aead.iv.length - td->salt.len; + else + iv_len = td->xform.chain.cipher.cipher.iv.length; + + iv_pos = test_ipsec_tunnel_hdr_len_get(td) + sizeof(struct rte_esp_hdr); + output_text += iv_pos; + + TEST_ASSERT(iv_len <= IV_LEN_MAX, "IV length greater than supported"); + + /* Compare against previous values */ + for (i = 0; i < index; i++) { + iv_tmp = &iv_queue[i * IV_LEN_MAX]; + + if (memcmp(output_text, iv_tmp, iv_len) == 0) { + printf("IV repeated"); + return TEST_FAILED; + } + } + + /* Save IV for future comparisons */ + + iv_tmp = &iv_queue[index * IV_LEN_MAX]; + memcpy(iv_tmp, output_text, iv_len); + index++; + + if (index == IPSEC_TEST_PACKETS_MAX) + index = 0; + + return TEST_SUCCESS; +} + +static int +test_ipsec_l3_csum_verify(struct rte_mbuf *m) +{ + uint16_t actual_cksum, expected_cksum; + struct rte_ipv4_hdr *ip; + + ip = rte_pktmbuf_mtod(m, struct rte_ipv4_hdr *); + + if (!is_ipv4((void *)ip)) + return TEST_SKIPPED; + + actual_cksum = ip->hdr_checksum; + + ip->hdr_checksum = 0; + + expected_cksum = rte_ipv4_cksum(ip); + + if (actual_cksum != expected_cksum) + return TEST_FAILED; + + return TEST_SUCCESS; +} + +static int +test_ipsec_l4_csum_verify(struct rte_mbuf *m) +{ + uint16_t actual_cksum = 0, expected_cksum = 0; + struct rte_ipv4_hdr *ipv4; + struct rte_ipv6_hdr *ipv6; + struct rte_tcp_hdr *tcp; + struct rte_udp_hdr *udp; + void *ip, *l4; + + ip = rte_pktmbuf_mtod(m, void *); + + if (is_ipv4(ip)) { + ipv4 = ip; + l4 = RTE_PTR_ADD(ipv4, sizeof(struct rte_ipv4_hdr)); + + switch (ipv4->next_proto_id) { + case IPPROTO_TCP: + tcp = (struct rte_tcp_hdr *)l4; + actual_cksum = tcp->cksum; + tcp->cksum = 0; + expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4); + break; + case IPPROTO_UDP: + udp = (struct rte_udp_hdr *)l4; + actual_cksum = udp->dgram_cksum; + udp->dgram_cksum = 0; + expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4); + break; + default: + break; + } + } else { + ipv6 = ip; + l4 = RTE_PTR_ADD(ipv6, sizeof(struct rte_ipv6_hdr)); + + switch (ipv6->proto) { + case IPPROTO_TCP: + tcp = (struct rte_tcp_hdr *)l4; + actual_cksum = tcp->cksum; + tcp->cksum = 0; + expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4); + break; + case IPPROTO_UDP: + udp = (struct rte_udp_hdr *)l4; + actual_cksum = udp->dgram_cksum; + udp->dgram_cksum = 0; + expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4); + break; + default: + break; + } + } + + if (actual_cksum != expected_cksum) + return TEST_FAILED; + + return TEST_SUCCESS; +} + static int test_ipsec_td_verify(struct rte_mbuf *m, const struct ipsec_test_data *td, bool silent, const struct ipsec_test_flags *flags) { uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *); uint32_t skip, len = rte_pktmbuf_pkt_len(m); + int ret; - /* For negative tests, no need to do verification */ - if (flags->icv_corrupt && - td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) + /* For tests with status as error for test success, skip verification */ + if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && + (flags->icv_corrupt || + flags->sa_expiry_pkts_hard || + flags->tunnel_hdr_verify)) return TEST_SUCCESS; + if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS && + flags->udp_encap) { + const struct rte_ipv4_hdr *iph4; + const struct rte_ipv6_hdr *iph6; + + if (td->ipsec_xform.tunnel.type == + RTE_SECURITY_IPSEC_TUNNEL_IPV4) { + iph4 = (const struct rte_ipv4_hdr *)output_text; + if (iph4->next_proto_id != IPPROTO_UDP) { + printf("UDP header is not found\n"); + return TEST_FAILED; + } + } else { + iph6 = (const struct rte_ipv6_hdr *)output_text; + if (iph6->proto != IPPROTO_UDP) { + printf("UDP header is not found\n"); + return TEST_FAILED; + } + } + + len -= sizeof(struct rte_udp_hdr); + output_text += sizeof(struct rte_udp_hdr); + } + if (len != td->output_text.len) { printf("Output length (%d) not matching with expected (%d)\n", len, td->output_text.len); @@ -236,6 +522,33 @@ test_ipsec_td_verify(struct rte_mbuf *m, const struct ipsec_test_data *td, len -= skip; output_text += skip; + if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) && + flags->ip_csum) { + if (m->ol_flags & PKT_RX_IP_CKSUM_GOOD) + ret = test_ipsec_l3_csum_verify(m); + else + ret = TEST_FAILED; + + if (ret == TEST_FAILED) + printf("Inner IP checksum test failed\n"); + + return ret; + } + + if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) && + flags->l4_csum) { + if (m->ol_flags & PKT_RX_L4_CKSUM_GOOD) + ret = test_ipsec_l4_csum_verify(m); + else + ret = TEST_FAILED; + + if (ret == TEST_FAILED) + printf("Inner L4 checksum test failed\n"); + + return ret; + } + + if (memcmp(output_text, td->output_text.data + skip, len)) { if (silent) return TEST_FAILED; @@ -279,6 +592,15 @@ test_ipsec_post_process(struct rte_mbuf *m, const struct ipsec_test_data *td, struct ipsec_test_data *res_d, bool silent, const struct ipsec_test_flags *flags) { + int ret; + + if (flags->iv_gen && + td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { + ret = test_ipsec_iv_verify_push(m, td); + if (ret != TEST_SUCCESS) + return ret; + } + /* * In case of known vector tests & all inbound tests, res_d provided * would be NULL and output data need to be validated against expected. @@ -301,10 +623,32 @@ test_ipsec_post_process(struct rte_mbuf *m, const struct ipsec_test_data *td, int test_ipsec_status_check(struct rte_crypto_op *op, const struct ipsec_test_flags *flags, - enum rte_security_ipsec_sa_direction dir) + enum rte_security_ipsec_sa_direction dir, + int pkt_num) { int ret = TEST_SUCCESS; + if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && + flags->sa_expiry_pkts_hard && + pkt_num == IPSEC_TEST_PACKETS_MAX) { + if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) { + printf("SA hard expiry (pkts) test failed\n"); + return TEST_FAILED; + } else { + return TEST_SUCCESS; + } + } + + if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) && + flags->tunnel_hdr_verify) { + if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) { + printf("Tunnel header verify test case failed\n"); + return TEST_FAILED; + } else { + return TEST_SUCCESS; + } + } + if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && flags->icv_corrupt) { if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) { printf("ICV corruption test case failed\n"); @@ -312,7 +656,16 @@ test_ipsec_status_check(struct rte_crypto_op *op, } } else { if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) { - printf("Security op processing failed\n"); + printf("Security op processing failed [pkt_num: %d]\n", + pkt_num); + ret = TEST_FAILED; + } + } + + if (flags->sa_expiry_pkts_soft && pkt_num == IPSEC_TEST_PACKETS_MAX) { + if (!(op->aux_flags & + RTE_CRYPTO_OP_AUX_FLAGS_IPSEC_SOFT_EXPIRY)) { + printf("SA soft expiry (pkts) test failed\n"); ret = TEST_FAILED; } }