aboutsummaryrefslogtreecommitdiff
path: root/example/ipsec_crypto/odp_ipsec_stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'example/ipsec_crypto/odp_ipsec_stream.c')
-rw-r--r--example/ipsec_crypto/odp_ipsec_stream.c747
1 files changed, 747 insertions, 0 deletions
diff --git a/example/ipsec_crypto/odp_ipsec_stream.c b/example/ipsec_crypto/odp_ipsec_stream.c
new file mode 100644
index 000000000..505ee900b
--- /dev/null
+++ b/example/ipsec_crypto/odp_ipsec_stream.c
@@ -0,0 +1,747 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2014-2018 Linaro Limited
+ */
+
+/** @cond _ODP_HIDE_FROM_DOXYGEN_ */
+
+/* enable strtok */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/des.h>
+#include <openssl/rand.h>
+#include <openssl/hmac.h>
+#include <openssl/opensslv.h>
+
+#include <odp_api.h>
+
+#include <odp/helper/odph_api.h>
+
+#include <odp_ipsec_stream.h>
+
+#define STREAM_MAGIC 0xBABE01234567CAFE
+
+#define LOOP_DEQ_COUNT 32 /**< packets to dequeue at once */
+
+/* Ignore warnings about APIs deprecated in OpenSSL 3.0 */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+/**
+ * Stream packet header
+ */
+typedef struct ODP_PACKED stream_pkt_hdr_s {
+ odp_u64be_t magic; /**< Stream magic value for verification */
+ uint8_t data[]; /**< Incrementing data stream */
+} stream_pkt_hdr_t;
+
+static const char *shm_name = "stream_db";
+stream_db_t *stream_db;
+
+void init_stream_db(void)
+{
+ odp_shm_t shm;
+
+ shm = odp_shm_reserve(shm_name,
+ sizeof(stream_db_t),
+ ODP_CACHE_LINE_SIZE,
+ 0);
+
+ if (shm == ODP_SHM_INVALID) {
+ ODPH_ERR("Error: shared mem reserve failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ stream_db = odp_shm_addr(shm);
+
+ if (stream_db == NULL) {
+ ODPH_ERR("Error: shared mem alloc failed.\n");
+ exit(EXIT_FAILURE);
+ }
+ memset(stream_db, 0, sizeof(*stream_db));
+}
+
+void deinit_stream_db(void)
+{
+ stream_db_entry_t *stream = NULL;
+
+ for (stream = stream_db->list; NULL != stream; stream = stream->next) {
+ free(stream->input.intf);
+ free(stream->output.intf);
+ }
+
+ odp_shm_t shm = odp_shm_lookup(shm_name);
+
+ if (shm == ODP_SHM_INVALID) {
+ ODPH_ERR("Error: shared mem not found.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (odp_shm_free(shm)) {
+ ODPH_ERR("Error: shared mem free failed.\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+int create_stream_db_entry(char *input)
+{
+ int pos = 0;
+ char *local;
+ char *str;
+ char *save;
+ char *token;
+ 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 (NULL == local)
+ return -1;
+ strcpy(local, input);
+
+ /* Setup for using "strtok_r" to search input string */
+ str = local;
+ save = NULL;
+
+ /* Parse tokens separated by ',' */
+ while (NULL != (token = strtok_r(str, ",", &save))) {
+ str = NULL; /* reset str for subsequent strtok_r calls */
+
+ /* Parse token based on its position */
+ 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.intf = strdup(token);
+ break;
+ case 3:
+ entry->output.intf = strdup(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:
+ printf("ERROR: extra token \"%s\" at position %d\n",
+ token, pos);
+ break;
+ }
+
+ /* Advance to next position */
+ pos++;
+ }
+
+ /* Verify we parsed exactly the number of tokens we expected */
+ if (6 != pos) {
+ printf("ERROR: \"%s\" contains %d tokens, expected 6\n",
+ input,
+ pos);
+ free(local);
+ return -1;
+ }
+
+ /* Add stream to the list */
+ entry->id = stream_db->index++;
+ entry->next = stream_db->list;
+ stream_db->list = entry;
+
+ free(local);
+ return 0;
+}
+
+static const EVP_MD *get_evp_md(odp_auth_alg_t auth)
+{
+ const EVP_MD *evp_md;
+
+ switch (auth) {
+ case ODP_AUTH_ALG_MD5_HMAC:
+ evp_md = EVP_md5();
+ break;
+ case ODP_AUTH_ALG_SHA1_HMAC:
+ evp_md = EVP_sha1();
+ break;
+ case ODP_AUTH_ALG_SHA256_HMAC:
+ evp_md = EVP_sha256();
+ break;
+ default:
+ evp_md = NULL;
+ }
+
+ return evp_md;
+}
+
+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;
+
+ stream->input.pktio = odp_pktio_lookup(stream->input.intf);
+
+ if (entry)
+ stream->evp_md = get_evp_md(entry->ah.alg);
+
+ /* Lookup output entry */
+ entry = find_ipsec_cache_entry_out(stream->src_ip,
+ stream->dst_ip,
+ 0);
+ stream->output.entry = entry;
+
+ stream->output.pktio = odp_pktio_lookup(stream->output.intf);
+
+ if (stream->evp_md == NULL && entry)
+ stream->evp_md = get_evp_md(entry->ah.alg);
+ }
+}
+
+odp_packet_t create_ipv4_packet(stream_db_entry_t *stream,
+ uint8_t *dmac,
+ odp_pool_t pkt_pool,
+ uint32_t max_len)
+{
+ ipsec_cache_entry_t *entry = NULL;
+ odp_packet_t pkt;
+ uint8_t *base;
+ uint8_t *data;
+ odph_ethhdr_t *eth;
+ odph_ipv4hdr_t *ip;
+ odph_ipv4hdr_t *inner_ip = NULL;
+ odph_ahhdr_t *ah = NULL;
+ odph_esphdr_t *esp = NULL;
+ odph_icmphdr_t *icmp;
+ stream_pkt_hdr_t *test;
+ unsigned i;
+
+ if (stream->input.entry)
+ entry = stream->input.entry;
+ else if (stream->output.entry)
+ entry = stream->output.entry;
+
+ /* Make sure there is enough space for protocol overhead */
+ if ((stream->length + 200) > max_len) {
+ ODPH_ERR("Error: too large test packet\n");
+ return ODP_PACKET_INVALID;
+ }
+
+ /* Get packet */
+ pkt = odp_packet_alloc(pkt_pool, max_len);
+ if (ODP_PACKET_INVALID == pkt) {
+ ODPH_ERR("Error: packet alloc failed\n");
+ return ODP_PACKET_INVALID;
+ }
+ base = odp_packet_data(pkt);
+ data = odp_packet_data(pkt);
+
+ /* Ethernet */
+ odp_packet_has_eth_set(pkt, 1);
+ eth = (odph_ethhdr_t *)data;
+ data += sizeof(*eth);
+
+ memset((char *)eth->src.addr, (0x80 | stream->id), ODPH_ETHADDR_LEN);
+ memcpy((char *)eth->dst.addr, dmac, ODPH_ETHADDR_LEN);
+ eth->type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4);
+
+ /* IPv4 */
+ odp_packet_has_ipv4_set(pkt, 1);
+ ip = (odph_ipv4hdr_t *)data;
+ data += sizeof(*ip);
+
+ /* Wait until almost finished to fill in mutable fields */
+ memset((char *)ip, 0, sizeof(*ip));
+ ip->ver_ihl = 0x45;
+ ip->id = odp_cpu_to_be_16(stream->id);
+ /* Outer IP header in tunnel mode */
+ if (entry && entry->mode == IPSEC_SA_MODE_TUNNEL &&
+ (entry == stream->input.entry)) {
+ ip->proto = ODPH_IPV4;
+ ip->src_addr = odp_cpu_to_be_32(entry->tun_src_ip);
+ ip->dst_addr = odp_cpu_to_be_32(entry->tun_dst_ip);
+ } else {
+ ip->proto = ODPH_IPPROTO_ICMPV4;
+ 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 && (entry == stream->input.entry) &&
+ (ODP_AUTH_ALG_NULL != entry->ah.alg)) {
+ if (entry->ah.alg != ODP_AUTH_ALG_MD5_HMAC &&
+ entry->ah.alg != ODP_AUTH_ALG_SHA1_HMAC &&
+ entry->ah.alg != ODP_AUTH_ALG_SHA256_HMAC)
+ abort();
+
+ ah = (odph_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 && (entry == stream->input.entry) &&
+ (ODP_CIPHER_ALG_NULL != entry->esp.alg)) {
+ if (ODP_CIPHER_ALG_3DES_CBC != entry->esp.alg)
+ abort();
+
+ esp = (odph_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);
+ }
+
+ /* Inner IP header in tunnel mode */
+ if (entry && (entry == stream->input.entry) &&
+ (entry->mode == IPSEC_SA_MODE_TUNNEL)) {
+ inner_ip = (odph_ipv4hdr_t *)data;
+ memset((char *)inner_ip, 0, sizeof(*inner_ip));
+ inner_ip->ver_ihl = 0x45;
+ inner_ip->tot_len = odp_cpu_to_be_16(sizeof(odph_ipv4hdr_t) +
+ sizeof(odph_icmphdr_t) +
+ sizeof(stream_pkt_hdr_t) +
+ stream->length);
+ inner_ip->proto = ODPH_IPPROTO_ICMPV4;
+ inner_ip->id = odp_cpu_to_be_16(stream->id);
+ inner_ip->ttl = 64;
+ inner_ip->tos = 0;
+ inner_ip->frag_offset = 0;
+ inner_ip->src_addr = odp_cpu_to_be_32(stream->src_ip);
+ inner_ip->dst_addr = odp_cpu_to_be_32(stream->dst_ip);
+ inner_ip->chksum = ~odp_chksum_ones_comp16(inner_ip,
+ sizeof(*inner_ip));
+ data += sizeof(*inner_ip);
+ }
+
+ /* ICMP header so we can see it on wireshark */
+ icmp = (odph_icmphdr_t *)data;
+ data += sizeof(*icmp);
+ icmp->type = ODPH_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_ones_comp16(icmp, data - (uint8_t *)icmp);
+
+ /* Close ESP if specified */
+ if (esp) {
+ int payload_len = data - (uint8_t *)icmp;
+ uint8_t *encrypt_start = (uint8_t *)icmp;
+
+ if (entry->mode == IPSEC_SA_MODE_TUNNEL) {
+ payload_len = data - (uint8_t *)inner_ip;
+ encrypt_start = (uint8_t *)inner_ip;
+ }
+
+ int encrypt_len;
+ odph_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);
+ for (int n = 0; n < encrypt_len - payload_len; n++)
+ *data++ = n + 1;
+
+ esp_t = (odph_esptrl_t *)(data) - 1;
+ esp_t->pad_len = encrypt_len - payload_len - sizeof(*esp_t);
+ esp_t->next_header = ip->proto;
+ ip->proto = ODPH_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(encrypt_start,
+ encrypt_start,
+ 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);
+
+ /* Close AH if specified */
+ if (ah) {
+ uint8_t hash[EVP_MAX_MD_SIZE];
+ int auth_len = data - (uint8_t *)ip;
+
+ ah->next_header = ip->proto;
+ ip->proto = ODPH_IPPROTO_AH;
+
+ HMAC(stream->evp_md,
+ entry->ah.key.data,
+ entry->ah.key.length,
+ (uint8_t *)ip,
+ auth_len,
+ hash,
+ NULL);
+
+ memcpy(ah->icv, hash, entry->ah.icv_len);
+ }
+
+ /* Correct set packet length offsets */
+ odp_packet_pull_tail(pkt, max_len - (data - base));
+ odp_packet_l2_offset_set(pkt, (uint8_t *)eth - base);
+ odp_packet_l3_offset_set(pkt, (uint8_t *)ip - base);
+ odp_packet_l4_offset_set(pkt, ((uint8_t *)ip - base) + sizeof(*ip));
+
+ /* Now fill in final IP header fields */
+ ip->ttl = 64;
+ ip->tos = 0;
+ ip->frag_offset = 0;
+ ip->chksum = 0;
+ odph_ipv4_csum_update(pkt);
+ return pkt;
+}
+
+odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream,
+ odp_packet_t pkt)
+{
+ ipsec_cache_entry_t *entry = NULL;
+ uint8_t *data;
+ odph_ipv4hdr_t *ip;
+ odph_ahhdr_t *ah = NULL;
+ odph_esphdr_t *esp = NULL;
+ int hdr_len;
+ odph_icmphdr_t *icmp;
+ stream_pkt_hdr_t *test;
+ uint32_t src_ip, dst_ip;
+
+ if (stream->input.entry)
+ entry = stream->input.entry;
+ else if (stream->output.entry)
+ entry = stream->output.entry;
+
+ /* Basic IPv4 verify (add checksum verification) */
+ data = odp_packet_l3_ptr(pkt, NULL);
+ ip = (odph_ipv4hdr_t *)data;
+ data += sizeof(*ip);
+ if (0x45 != ip->ver_ihl)
+ return FALSE;
+
+ src_ip = odp_be_to_cpu_32(ip->src_addr);
+ dst_ip = odp_be_to_cpu_32(ip->dst_addr);
+ if ((stream->src_ip != src_ip) && stream->output.entry &&
+ (stream->output.entry->tun_src_ip != src_ip))
+ return FALSE;
+ if ((stream->dst_ip != dst_ip) && stream->output.entry &&
+ (stream->output.entry->tun_dst_ip != dst_ip))
+ return FALSE;
+
+ if ((stream->src_ip != src_ip) && stream->input.entry &&
+ (stream->input.entry->tun_src_ip != src_ip))
+ return FALSE;
+ if ((stream->dst_ip != dst_ip) && stream->input.entry &&
+ (stream->input.entry->tun_dst_ip != dst_ip))
+ return FALSE;
+
+ /* Find IPsec headers if any and compare against entry */
+ hdr_len = locate_ipsec_headers(ip, &ah, &esp);
+
+ /* Verify if the packet is IPsec encapsulated or is cleartext as
+ * expected
+ */
+ if (((stream->output.entry && (!ah && !esp))) ||
+ (stream->input.entry && (ah || esp)))
+ return FALSE;
+
+ /* Cleartext packet */
+ if (!ah && !esp)
+ goto clear_packet;
+ 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_HMAC != entry->ah.alg &&
+ ODP_AUTH_ALG_SHA1_HMAC != entry->ah.alg &&
+ ODP_AUTH_ALG_SHA256_HMAC != 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[entry->ah.icv_len];
+ uint8_t hash[EVP_MAX_MD_SIZE];
+
+ /* 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, entry->ah.icv_len);
+ memset(ah->icv, 0, entry->ah.icv_len);
+
+ /* Calculate HMAC and compare */
+ HMAC(stream->evp_md,
+ entry->ah.key.data,
+ entry->ah.key.length,
+ (uint8_t *)ip,
+ odp_be_to_cpu_16(ip->tot_len),
+ hash,
+ NULL);
+
+ 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) {
+ odph_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 = (odph_esptrl_t *)(data + encrypt_len) - 1;
+ ip->proto = esp_t->next_header;
+ }
+
+clear_packet:
+ /* Verify IP/ICMP packet */
+ if (entry && (entry->mode == IPSEC_SA_MODE_TUNNEL) && (ah || esp)) {
+ if (ODPH_IPV4 != ip->proto)
+ return FALSE;
+ odph_ipv4hdr_t *inner_ip = (odph_ipv4hdr_t *)data;
+
+ icmp = (odph_icmphdr_t *)(inner_ip + 1);
+ data = (uint8_t *)icmp;
+ } else {
+ if (ODPH_IPPROTO_ICMPV4 != ip->proto)
+ return FALSE;
+ icmp = (odph_icmphdr_t *)data;
+ }
+
+ /* Verify ICMP header */
+ data += sizeof(*icmp);
+ if (ODPH_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_pool_t pkt_pool;
+ odp_pool_info_t pool_info;
+ stream_db_entry_t *stream = NULL;
+ uint32_t max_len;
+
+ /* Lookup the packet pool */
+ pkt_pool = odp_pool_lookup("packet_pool");
+ if (pkt_pool == ODP_POOL_INVALID) {
+ ODPH_ERR("Error: pkt_pool not found\n");
+ return -1;
+ }
+ if (odp_pool_info(pkt_pool, &pool_info)) {
+ ODPH_ERR("Error: pool info failed\n");
+ return -1;
+ }
+
+ /* Only single segment packets are supported */
+ max_len = pool_info.params.pkt.seg_len;
+
+ /* For each stream create corresponding input packets */
+ for (stream = stream_db->list; NULL != stream; stream = stream->next) {
+ int count;
+ int ret;
+ uint8_t dmac[ODPH_ETHADDR_LEN];
+ odp_pktout_queue_t queue;
+
+ ret = odp_pktio_mac_addr(stream->input.pktio,
+ dmac, sizeof(dmac));
+ if (ret <= 0) {
+ ODPH_ERR("Error: failed during MAC address get for "
+ "%s\n", stream->input.intf);
+ continue;
+ }
+
+ ret = odp_pktout_queue(stream->input.pktio, &queue, 1);
+ if (ret < 1) {
+ ODPH_ERR("Error: failed to get outqueue for %s\n",
+ stream->input.intf);
+ continue;
+ }
+
+ for (count = stream->count; count > 0; count--) {
+ odp_packet_t pkt;
+
+ pkt = create_ipv4_packet(stream, dmac, pkt_pool, max_len);
+ if (ODP_PACKET_INVALID == pkt) {
+ ODPH_ERR("Error: packet buffers exhausted\n");
+ break;
+ }
+ stream->created++;
+ if (odp_pktout_send(queue, &pkt, 1) != 1) {
+ odp_packet_free(pkt);
+ ODPH_ERR("Error: queue enqueue failed\n");
+ break;
+ }
+
+ /* Count this stream when we create first packet */
+ if (1 == stream->created)
+ created++;
+ }
+ }
+ if ((stream_db->index > 0) && created == 0) {
+ ODPH_ERR("Error: failed to create any input streams\n");
+ return -1;
+ }
+
+ return created;
+}
+
+odp_bool_t verify_stream_db_outputs(void)
+{
+ odp_bool_t done = TRUE;
+ stream_db_entry_t *stream = NULL;
+ const char *env;
+
+ env = getenv("ODP_IPSEC_STREAM_VERIFY_MDEQ");
+ /* For each stream look for output packets */
+ for (stream = stream_db->list; NULL != stream; stream = stream->next) {
+ int idx;
+ int count;
+ int ret;
+ odp_queue_t queue;
+ odp_event_t ev_tbl[LOOP_DEQ_COUNT];
+
+ ret = odp_pktin_event_queue(stream->output.pktio, &queue, 1);
+ if (ret < 1) {
+ ODPH_ERR("Error: failed to get inqueue for %s\n",
+ stream->output.intf);
+ continue;
+ }
+
+ for (;;) {
+ if (env) {
+ count = odp_queue_deq_multi(queue,
+ ev_tbl,
+ LOOP_DEQ_COUNT);
+ } else {
+ ev_tbl[0] = odp_queue_deq(queue);
+ count = (ev_tbl[0] != ODP_EVENT_INVALID) ?
+ 1 : 0;
+ }
+ if (!count)
+ break;
+ for (idx = 0; idx < count; idx++) {
+ odp_bool_t good;
+ odp_packet_t pkt;
+
+ pkt = odp_packet_from_event(ev_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;
+}