From patchwork Thu Aug 21 12:30:37 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robbie King X-Patchwork-Id: 35759 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qc0-f197.google.com (mail-qc0-f197.google.com [209.85.216.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id E23282055D for ; Thu, 21 Aug 2014 12:31:33 +0000 (UTC) Received: by mail-qc0-f197.google.com with SMTP id c9sf28230666qcz.4 for ; Thu, 21 Aug 2014 05:31:33 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:subject:precedence:list-id:list-unsubscribe:list-archive :list-post:list-help:list-subscribe:mime-version:errors-to:sender :x-original-sender:x-original-authentication-results:mailing-list :content-type:content-transfer-encoding; bh=7QdTJSBxsQxgmOGWCT+FZDFFJgj+shszQruRGbDY3l4=; b=dVHBAUdwvlyoIp8PF4yyLuPhufounAJEMIEX2GsVuTWnp/+bDtYxDzVCQs3TkMVlZw nlQlvnNfwZ2XzViQqoest9G728jkGYCB4cAhhN2QtFpXmuqZ1VfMlrK2yAqcB7g87M71 UNYM4jsXttfnEkjjhO4t34+WyqsYfip3Lu3SAZiYCwpjVLrfrkN8e/hvfQf8rKfDataZ 58eF/s48KTwhEMsrOWnRvL56ko3FnWXJiLIAUiV/AC8yvxfiiPzxT2635qSAM2IAtzPa JuS2drTHlzcAZThbry4aJ3kgDuzPpmzT6ZDsEZWD/oTytKcVMwxaih/l+0O6FMHhrRP5 U8Qg== X-Gm-Message-State: ALoCoQkA6M4mcS6EUPwyTCuLuhFZP1G9n1twvtK4vrXAvOAoTNzCJI4R2rc2nzx7UpbKlNfN7iJQ X-Received: by 10.236.55.71 with SMTP id j47mr23992731yhc.36.1408624293710; Thu, 21 Aug 2014 05:31:33 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.49.235 with SMTP id q98ls697442qga.91.gmail; Thu, 21 Aug 2014 05:31:33 -0700 (PDT) X-Received: by 10.220.184.70 with SMTP id cj6mr41508616vcb.5.1408624293621; Thu, 21 Aug 2014 05:31:33 -0700 (PDT) Received: from mail-vc0-x22e.google.com (mail-vc0-x22e.google.com [2607:f8b0:400c:c03::22e]) by mx.google.com with ESMTPS id hn5si12249035vdb.51.2014.08.21.05.31.33 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 21 Aug 2014 05:31:33 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2607:f8b0:400c:c03::22e as permitted sender) client-ip=2607:f8b0:400c:c03::22e; Received: by mail-vc0-f174.google.com with SMTP id la4so10474107vcb.5 for ; Thu, 21 Aug 2014 05:31:33 -0700 (PDT) X-Received: by 10.220.184.70 with SMTP id cj6mr41508608vcb.5.1408624293525; Thu, 21 Aug 2014 05:31:33 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.45.67 with SMTP id uj3csp131519vcb; Thu, 21 Aug 2014 05:31:33 -0700 (PDT) X-Received: by 10.140.32.134 with SMTP id h6mr84063966qgh.49.1408624292904; Thu, 21 Aug 2014 05:31:32 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id k4si2022165qao.13.2014.08.21.05.31.32 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Thu, 21 Aug 2014 05:31:32 -0700 (PDT) Received-SPF: none (google.com: lng-odp-bounces@lists.linaro.org does not designate permitted sender hosts) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1XKRWd-0004dB-N6; Thu, 21 Aug 2014 12:31:31 +0000 Received: from rcdn-iport-3.cisco.com ([173.37.86.74]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1XKRVv-0004Yd-96 for lng-odp@lists.linaro.org; Thu, 21 Aug 2014 12:30:47 +0000 X-IronPort-AV: E=Sophos;i="5.01,909,1400025600"; d="scan'208";a="349237378" Received: from rcdn-core-7.cisco.com ([173.37.93.143]) by rcdn-iport-3.cisco.com with ESMTP; 21 Aug 2014 12:30:41 +0000 Received: from cpp-rtpbld-55.cisco.com (cpp-rtpbld-55.cisco.com [172.18.5.199]) by rcdn-core-7.cisco.com (8.14.5/8.14.5) with ESMTP id s7LCUfYJ015421 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 21 Aug 2014 12:30:41 GMT Received: from cpp-rtpbld-55.cisco.com (localhost.localdomain [127.0.0.1]) by cpp-rtpbld-55.cisco.com (8.13.8/8.13.8) with ESMTP id s7LCUfCh012536; Thu, 21 Aug 2014 08:30:41 -0400 Received: (from robking@localhost) by cpp-rtpbld-55.cisco.com (8.13.8/8.13.8/Submit) id s7LCUfiS012535; Thu, 21 Aug 2014 08:30:41 -0400 From: Robbie King To: lng-odp@lists.linaro.org Date: Thu, 21 Aug 2014 08:30:37 -0400 Message-Id: <1408624238-12430-13-git-send-email-robking@cisco.com> X-Mailer: git-send-email 1.9.2 In-Reply-To: <1408624238-12430-1-git-send-email-robking@cisco.com> References: <1408624238-12430-1-git-send-email-robking@cisco.com> X-Topics: patch Subject: [lng-odp] [PATCH 12/13] IPsec example stream DB and check/verify X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: lng-odp-bounces@lists.linaro.org X-Original-Sender: robking@cisco.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 2607:f8b0:400c:c03::22e as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org; dkim=fail header.i=@cisco.com Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Signed-off-by: Robbie King --- example/ipsec/odp_ipsec_stream.c | 534 ++++++++++++++++++++++++++++++++++++++ example/ipsec/odp_ipsec_stream.h | 133 ++++++++++ 2 files changed, 667 insertions(+), 0 deletions(-) create mode 100644 example/ipsec/odp_ipsec_stream.c create mode 100644 example/ipsec/odp_ipsec_stream.h diff --git a/example/ipsec/odp_ipsec_stream.c b/example/ipsec/odp_ipsec_stream.c new file mode 100644 index 0000000..02de790 --- /dev/null +++ b/example/ipsec/odp_ipsec_stream.c @@ -0,0 +1,534 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STREAM_MAGIC 0xBABE01234567CAFE + +#define LOOP_DEQ_MULTIPLE 0 /**< enable multi packet dequeue */ + +/** + * Stream packet header + */ +typedef struct ODP_PACKED stream_pkt_hdr_s { + uint64be_t magic; /**< Stream magic value for verification */ + uint8_t data[0]; /**< Incrementing data stream */ +} stream_pkt_hdr_t; + +stream_db_t *stream_db; + +void init_stream_db(void) +{ + stream_db = odp_shm_reserve("stream_db", + sizeof(stream_db_t), + ODP_CACHE_LINE_SIZE); + if (stream_db == NULL) { + ODP_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(stream_db, 0, sizeof(*stream_db)); +} + +int create_stream_db_entry(char *input) +{ + int pos; + char *local, *str, *save; + stream_db_entry_t *entry = &stream_db->array[stream_db->index]; + + /* Verify we have a good entry */ + if (MAX_DB <= stream_db->index) + return -1; + + /* Make a local copy */ + local = malloc(strlen(input) + 1); + if (local == NULL) + return -1; + strcpy(local, input); + + /* count the number of tokens separated by ',' */ + for (str = local, save = NULL, pos = 0;; str = NULL, pos++) { + char *token = strtok_r(str, ":", &save); + + /* Check for no more tokens */ + if (token == NULL) + break; + + /* Parse based on postion */ + switch (pos) { + case 0: + parse_ipv4_string(token, &entry->src_ip, NULL); + break; + case 1: + parse_ipv4_string(token, &entry->dst_ip, NULL); + break; + case 2: + entry->input.loop = loop_if_index(token); + if (entry->input.loop < 0) { + ODP_ERR("Error: stream must have input loop\n"); + exit(EXIT_FAILURE); + } + break; + case 3: + entry->output.loop = loop_if_index(token); + break; + case 4: + entry->count = atoi(token); + break; + case 5: + entry->length = atoi(token); + if (entry->length < sizeof(stream_pkt_hdr_t)) + entry->length = 0; + else + entry->length -= sizeof(stream_pkt_hdr_t); + break; + default: + return -1; + } + } + + /* Verify all positions filled */ + if (6 != pos) + return -1; + + /* Add stream to the list */ + entry->id = stream_db->index++; + entry->next = stream_db->list; + stream_db->list = entry; + + return 0; +} + +void resolve_stream_db(void) +{ + stream_db_entry_t *stream = NULL; + + /* For each stream look for input and output IPsec entries */ + for (stream = stream_db->list; NULL != stream; stream = stream->next) { + ipsec_cache_entry_t *entry; + + /* Lookup input entry */ + entry = find_ipsec_cache_entry_in(stream->src_ip, + stream->dst_ip, + NULL, + NULL); + stream->input.entry = entry; + + /* Lookup output entry */ + entry = find_ipsec_cache_entry_out(stream->src_ip, + stream->dst_ip, + 0); + stream->output.entry = entry; + } +} + +odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, + uint8_t *dmac, + odp_buffer_pool_t pkt_pool) +{ + ipsec_cache_entry_t *entry = stream->input.entry; + odp_buffer_t bfr; + odp_packet_t pkt; + uint8_t *base; + uint8_t *data; + odp_ethhdr_t *eth; + odp_ipv4hdr_t *ip; + odp_ahhdr_t *ah = NULL; + odp_esphdr_t *esp = NULL; + odp_icmphdr_t *icmp; + stream_pkt_hdr_t *test; + uint i; + + /* Get buffer */ + bfr = odp_buffer_alloc(pkt_pool); + if (ODP_BUFFER_INVALID == bfr) + return ODP_PACKET_INVALID; + pkt = odp_packet_from_buffer(bfr); + odp_packet_init(pkt); + base = odp_packet_start(pkt); + data = odp_packet_start(pkt); + + /* Ethernet */ + odp_packet_set_inflag_eth(pkt, 1); + odp_packet_set_l2_offset(pkt, data - base); + eth = (odp_ethhdr_t *)data; + data += sizeof(*eth); + + memset((char *)eth->src.addr, (0x80 | stream->id), ODP_ETHADDR_LEN); + memcpy((char *)eth->dst.addr, dmac, ODP_ETHADDR_LEN); + eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4); + + /* IPv4 */ + odp_packet_set_inflag_ipv4(pkt, 1); + odp_packet_set_l3_offset(pkt, data - base); + ip = (odp_ipv4hdr_t *)data; + data += sizeof(*ip); + odp_packet_set_l4_offset(pkt, data - base); + + /* Wait until almost finished to fill in mutable fields */ + memset((char *)ip, 0, sizeof(*ip)); + ip->ver_ihl = 0x45; + ip->proto = ODP_IPPROTO_ICMP; + ip->id = odp_cpu_to_be_16(stream->id); + ip->src_addr = odp_cpu_to_be_32(stream->src_ip); + ip->dst_addr = odp_cpu_to_be_32(stream->dst_ip); + + /* AH (if specified) */ + if (entry && (ODP_AUTH_ALG_NULL != entry->ah.alg)) { + if (ODP_AUTH_ALG_MD5_96 != entry->ah.alg) + abort(); + + ah = (odp_ahhdr_t *)data; + data += sizeof(*ah); + data += entry->ah.icv_len; + + memset((char *)ah, 0, sizeof(*ah) + entry->ah.icv_len); + ah->ah_len = 1 + (entry->ah.icv_len / 4); + ah->spi = odp_cpu_to_be_32(entry->ah.spi); + ah->seq_no = odp_cpu_to_be_32(stream->input.ah_seq++); + } + + /* ESP (if specified) */ + if (entry && (ODP_CIPHER_ALG_NULL != entry->esp.alg)) { + if (ODP_CIPHER_ALG_3DES_CBC != entry->esp.alg) + abort(); + + esp = (odp_esphdr_t *)data; + data += sizeof(*esp); + data += entry->esp.iv_len; + + esp->spi = odp_cpu_to_be_32(entry->esp.spi); + esp->seq_no = odp_cpu_to_be_32(stream->input.esp_seq++); + RAND_bytes(esp->iv, 8); + } + + /* ICMP header so we can see it on wireshark */ + icmp = (odp_icmphdr_t *)data; + data += sizeof(*icmp); + icmp->type = ICMP_ECHO; + icmp->code = 0; + icmp->un.echo.id = odp_cpu_to_be_16(0x1234); + icmp->un.echo.sequence = odp_cpu_to_be_16(stream->created); + + /* Packet payload of incrementing bytes */ + test = (stream_pkt_hdr_t *)data; + data += sizeof(*test); + test->magic = odp_cpu_to_be_64(STREAM_MAGIC); + for (i = 0; i < stream->length; i++) + *data++ = (uint8_t)i; + + /* Close ICMP */ + icmp->chksum = 0; + icmp->chksum = odp_chksum(icmp, data - (uint8_t *)icmp); + + /* Close ESP if specified */ + if (esp) { + int payload_len = data - (uint8_t *)icmp; + int encrypt_len; + odp_esptrl_t *esp_t; + DES_key_schedule ks1, ks2, ks3; + uint8_t iv[8]; + + memcpy(iv, esp->iv, sizeof(iv)); + + encrypt_len = ESP_ENCODE_LEN(payload_len + sizeof(*esp_t), + entry->esp.block_len); + memset(data, 0, encrypt_len - payload_len); + data += encrypt_len - payload_len; + + esp_t = (odp_esptrl_t *)(data) - 1; + esp_t->pad_len = encrypt_len - payload_len - sizeof(*esp_t); + esp_t->next_header = ip->proto; + ip->proto = ODP_IPPROTO_ESP; + + DES_set_key((DES_cblock *)&entry->esp.key.data[0], &ks1); + DES_set_key((DES_cblock *)&entry->esp.key.data[8], &ks2); + DES_set_key((DES_cblock *)&entry->esp.key.data[16], &ks3); + + DES_ede3_cbc_encrypt((uint8_t *)icmp, + (uint8_t *)icmp, + encrypt_len, + &ks1, + &ks2, + &ks3, + (DES_cblock *)iv, + 1); + } + + /* Since ESP can pad we can now fix IP length */ + ip->tot_len = odp_cpu_to_be_16(data - (uint8_t *)ip); + odp_packet_set_len(pkt, data - base); + + /* Close AH if specified */ + if (ah) { + uint8_t hash[EVP_MAX_MD_SIZE]; + uint32_t hash_len = 12; + int auth_len = data - (uint8_t *)ip; + + ah->next_header = ip->proto; + ip->proto = ODP_IPPROTO_AH; + + HMAC(EVP_md5(), + entry->ah.key.data, + 16, + (uint8_t *)ip, + auth_len, + hash, + &hash_len); + + memcpy(ah->icv, hash, 12); + } + + /* Now fill in final IP header fields */ + ip->ttl = 64; + ip->tos = 0; + ip->frag_offset = 0; + ip->chksum = 0; + odp_ipv4_csum_update(pkt); + return pkt; +} + +bool verify_ipv4_packet(stream_db_entry_t *stream, + odp_packet_t pkt) +{ + ipsec_cache_entry_t *entry = stream->output.entry; + uint8_t *data; + odp_ipv4hdr_t *ip; + odp_ahhdr_t *ah = NULL; + odp_esphdr_t *esp = NULL; + int hdr_len; + odp_icmphdr_t *icmp; + stream_pkt_hdr_t *test; + + /* Basic IPv4 verify (add checksum verification) */ + data = odp_packet_l3(pkt); + ip = (odp_ipv4hdr_t *)data; + data += sizeof(*ip); + if (0x45 != ip->ver_ihl) + return FALSE; + if (stream->src_ip != odp_be_to_cpu_32(ip->src_addr)) + return FALSE; + if (stream->dst_ip != odp_be_to_cpu_32(ip->dst_addr)) + return FALSE; + + /* Find IPsec headers if any and compare against entry */ + hdr_len = locate_ipsec_headers(ip, &ah, &esp); + if (ah) { + if (!entry) + return FALSE; + if (ODP_AUTH_ALG_NULL == entry->ah.alg) + return FALSE; + if (odp_be_to_cpu_32(ah->spi) != entry->ah.spi) + return FALSE; + if (ODP_AUTH_ALG_MD5_96 != entry->ah.alg) + abort(); + } else { + if (entry && (ODP_AUTH_ALG_NULL != entry->ah.alg)) + return FALSE; + } + if (esp) { + if (!entry) + return FALSE; + if (ODP_CIPHER_ALG_NULL == entry->esp.alg) + return FALSE; + if (odp_be_to_cpu_32(esp->spi) != entry->esp.spi) + return FALSE; + if (ODP_CIPHER_ALG_3DES_CBC != entry->esp.alg) + abort(); + hdr_len += entry->esp.iv_len; + } else { + if (entry && (ODP_CIPHER_ALG_NULL != entry->esp.alg)) + return FALSE; + } + data += hdr_len; + + /* Verify authentication (if present) */ + if (ah) { + uint8_t ip_tos; + uint8_t ip_ttl; + uint16_t ip_frag_offset; + uint8_t icv[12]; + uint8_t hash[EVP_MAX_MD_SIZE]; + uint32_t hash_len = 12; + + /* Save/clear mutable fields */ + ip_tos = ip->tos; + ip_ttl = ip->ttl; + ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset); + ip->tos = 0; + ip->ttl = 0; + ip->frag_offset = 0; + ip->chksum = 0; + memcpy(icv, ah->icv, 12); + memset(ah->icv, 0, 12); + + /* Calculate HMAC and compare */ + HMAC(EVP_md5(), + entry->ah.key.data, + entry->ah.key.length, + (uint8_t *)ip, + odp_be_to_cpu_16(ip->tot_len), + hash, + &hash_len); + + if (0 != memcmp(icv, hash, sizeof(icv))) + return FALSE; + + ip->proto = ah->next_header; + ip->tos = ip_tos; + ip->ttl = ip_ttl; + ip->frag_offset = odp_cpu_to_be_16(ip_frag_offset); + } + + /* Decipher if present */ + if (esp) { + odp_esptrl_t *esp_t; + DES_key_schedule ks1, ks2, ks3; + uint8_t iv[8]; + int encrypt_len = ipv4_data_len(ip) - hdr_len; + + memcpy(iv, esp->iv, sizeof(iv)); + + DES_set_key((DES_cblock *)&entry->esp.key.data[0], &ks1); + DES_set_key((DES_cblock *)&entry->esp.key.data[8], &ks2); + DES_set_key((DES_cblock *)&entry->esp.key.data[16], &ks3); + + DES_ede3_cbc_encrypt((uint8_t *)data, + (uint8_t *)data, + encrypt_len, + &ks1, + &ks2, + &ks3, + (DES_cblock *)iv, + 0); + + esp_t = (odp_esptrl_t *)(data + encrypt_len) - 1; + ip->proto = esp_t->next_header; + } + + /* Verify ICMP packet */ + if (ODP_IPPROTO_ICMP != ip->proto) + return FALSE; + + /* Verify ICMP header */ + icmp = (odp_icmphdr_t *)data; + data += sizeof(*icmp); + if (ICMP_ECHO != icmp->type) + return FALSE; + if (0x1234 != odp_be_to_cpu_16(icmp->un.echo.id)) + return FALSE; + + /* Now check our packet */ + test = (stream_pkt_hdr_t *)data; + if (STREAM_MAGIC != odp_be_to_cpu_64(test->magic)) + return FALSE; + + return TRUE; +} + +int create_stream_db_inputs(void) +{ + int created = 0; + odp_buffer_pool_t pkt_pool; + stream_db_entry_t *stream = NULL; + + /* Lookup the packet pool */ + pkt_pool = odp_buffer_pool_lookup("packet_pool"); + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { + ODP_ERR("Error: pkt_pool not found\n"); + exit(EXIT_FAILURE); + } + + /* For each stream create corresponding input packets */ + for (stream = stream_db->list; NULL != stream; stream = stream->next) { + int count; + uint8_t *dmac = query_loopback_db_mac(stream->input.loop); + odp_queue_t queue = query_loopback_db_inq(stream->input.loop); + + for (count = stream->count; count > 0; count--) { + odp_packet_t pkt; + + pkt = create_ipv4_packet(stream, dmac, pkt_pool); + if (ODP_PACKET_INVALID == pkt) { + printf("Packet buffers exhausted\n"); + break; + } + stream->created++; + odp_queue_enq(queue, pkt); + + /* Count this stream when we create first packet */ + if (1 == stream->created) + created++; + } + } + + return created; +} + +bool verify_stream_db_outputs(void) +{ + bool done = TRUE; + stream_db_entry_t *stream = NULL; + + /* For each stream look for output packets */ + for (stream = stream_db->list; NULL != stream; stream = stream->next) { + int idx; + int count; + odp_queue_t queue; + odp_buffer_t buf_tbl[32]; + + queue = query_loopback_db_outq(stream->output.loop); + + if (ODP_QUEUE_INVALID == queue) + continue; + + for (;;) { +#if LOOP_DEQ_MULTIPLE + count = odp_queue_deq_multi(queue, buf_tbl, 32); +#else + buf_tbl[0] = odp_queue_deq(queue); + count = (buf_tbl[0] != ODP_BUFFER_INVALID) ? 1 : 0; +#endif + if (!count) + break; + for (idx = 0; idx < count; idx++) { + bool good; + odp_packet_t pkt; + + pkt = odp_packet_from_buffer(buf_tbl[idx]); + + good = verify_ipv4_packet(stream, pkt); + if (good) + stream->verified++; + odp_packet_free(pkt); + } + } + + printf("Stream %d %d\n", stream->created, stream->verified); + + if (stream->created != stream->verified) + done = FALSE; + } + return done; +} + diff --git a/example/ipsec/odp_ipsec_stream.h b/example/ipsec/odp_ipsec_stream.h new file mode 100644 index 0000000..d3a0dd4 --- /dev/null +++ b/example/ipsec/odp_ipsec_stream.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_IPSEC_STREAM_H_ +#define ODP_IPSEC_STREAM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * Stream database entry structure + */ +typedef struct stream_db_entry_s { + struct stream_db_entry_s *next; /**< Next entry on list */ + int id; /**< Stream ID */ + uint32_t src_ip; /**< Source IPv4 address */ + uint32_t dst_ip; /**< Destination IPv4 address */ + int count; /**< Packet count */ + uint length; /**< Packet payload length */ + uint32_t created; /**< Number successfully created */ + uint32_t verified; /**< Number successfully verified */ + struct { + int loop; /**< Input loop interface index */ + uint32_t ah_seq; /**< AH sequence number if present */ + uint32_t esp_seq; /**< ESP sequence number if present */ + ipsec_cache_entry_t *entry; /**< IPsec to apply on input */ + } input; + struct { + int loop; /**< Output loop interface index */ + ipsec_cache_entry_t *entry; /**t IPsec to verify on output */ + } output; +} stream_db_entry_t; + +/** + * Stream database + */ +typedef struct stream_db_s { + uint32_t index; /**< Index of next available entry */ + stream_db_entry_t *list; /**< List of active entries */ + stream_db_entry_t array[MAX_DB]; /**< Entry storage */ +} stream_db_t; + +extern stream_db_t *stream_db; + +/** Initialize stream database global control structure */ +void init_stream_db(void); + +/** + * Create an stream DB entry + * + * String is of the format "SrcIP:DstIP:InInt:OutIntf:Count:Length" + * + * @param input Pointer to string describing stream + * + * @return 0 if successful else -1 + */ +int create_stream_db_entry(char *input); + +/** + * Resolve the stream DB against the IPsec input and output caches + * + * For each stream, look the source and destination IP address up in the + * input and output IPsec caches. If a hit is found, store the hit in + * the stream DB to be used when creating packets. + */ +void resolve_stream_db(void); + +/** + * Create IPv4 packet for stream + * + * Create one ICMP test packet based on the stream structure. If an input + * IPsec cache entry is associated with the stream, build a packet that should + * successfully match that entry and be correctly decoded by it. + * + * @param stream Stream DB entry + * @param dmac Destination MAC address to use + * @param pkt_pool Packet buffer pool to allocate from + * + * @return packet else ODP_PACKET_INVALID + */ +odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, + uint8_t *dmac, + odp_buffer_pool_t pkt_pool); + +/** + * Verify an IPv4 packet received on a loop output queue + * + * TODO: Better error checking, add counters, add tracing, + * add order verification + * + * @param stream Stream to verify the packet against + * @param pkt Packet to verify + * + * @return TRUE if packet verifies else FALSE + */ +bool verify_ipv4_packet(stream_db_entry_t *stream, + odp_packet_t pkt); + +/** + * Create input packets based on the stream DB + * + * Create input packets based on the configured streams and enqueue them + * into loop interface input queues. Once packet processing starts these + * packets will be remomved and processed as if they had come from a normal + * packet interface. + * + * @return number of streams successfully processed + */ +int create_stream_db_inputs(void); + +/** + * Verify stream DB outputs + * + * For each stream, poll the output loop interface queue and verify + * any packets found on it + * + * @return TRUE if all packets on all streams verified else FALSE + */ +bool verify_stream_db_outputs(void); + +#ifdef __cplusplus +} +#endif + +#endif