From 6e24d8da43d4780372df9cb9d77ff35cdd065cf6 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 10 Sep 2020 16:55:57 +0300 Subject: example: ipsec_crypto: rename ipsec application to ipsec_crypto Rename ipsec application to ipsec_crypto to better distinguish it from the ipsec api example. Signed-off-by: Matias Elo Reviewed-by: Janne Peltonen --- doc/application-api-guide/examples.dox | 10 +- example/Makefile.am | 2 +- example/ipsec/.gitignore | 1 - example/ipsec/Makefile.am | 57 - example/ipsec/README | 169 -- example/ipsec/odp_ipsec.c | 1658 -------------------- example/ipsec/odp_ipsec_cache.c | 243 --- example/ipsec/odp_ipsec_cache.h | 136 -- example/ipsec/odp_ipsec_fwd_db.c | 173 -- example/ipsec/odp_ipsec_fwd_db.h | 98 -- example/ipsec/odp_ipsec_misc.h | 343 ---- example/ipsec/odp_ipsec_run_ah_in.sh | 12 - example/ipsec/odp_ipsec_run_ah_out.sh | 12 - example/ipsec/odp_ipsec_run_both_in.sh | 14 - example/ipsec/odp_ipsec_run_both_out.sh | 14 - example/ipsec/odp_ipsec_run_esp_in.sh | 13 - example/ipsec/odp_ipsec_run_esp_out.sh | 18 - example/ipsec/odp_ipsec_run_live.sh | 17 - example/ipsec/odp_ipsec_run_router.sh | 9 - example/ipsec/odp_ipsec_run_simple.sh | 15 - example/ipsec/odp_ipsec_sa_db.c | 328 ---- example/ipsec/odp_ipsec_sa_db.h | 131 -- example/ipsec/odp_ipsec_sp_db.c | 159 -- example/ipsec/odp_ipsec_sp_db.h | 71 - example/ipsec/odp_ipsec_stream.c | 678 -------- example/ipsec/odp_ipsec_stream.h | 135 -- example/ipsec_api/odp_ipsec_fwd_db.c | 2 +- example/ipsec_api/odp_ipsec_fwd_db.h | 2 +- example/ipsec_api/odp_ipsec_misc.h | 2 +- example/ipsec_api/odp_ipsec_sa_db.c | 2 +- example/ipsec_api/odp_ipsec_sa_db.h | 2 +- example/ipsec_api/odp_ipsec_sp_db.c | 2 +- example/ipsec_api/odp_ipsec_sp_db.h | 2 +- example/ipsec_api/odp_ipsec_stream.c | 2 +- example/ipsec_api/odp_ipsec_stream.h | 2 +- example/ipsec_crypto/.gitignore | 1 + example/ipsec_crypto/Makefile.am | 58 + example/ipsec_crypto/README | 171 ++ example/ipsec_crypto/odp_ipsec.c | 1658 ++++++++++++++++++++ example/ipsec_crypto/odp_ipsec_cache.c | 243 +++ example/ipsec_crypto/odp_ipsec_cache.h | 136 ++ example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh | 12 + .../ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh | 12 + .../ipsec_crypto/odp_ipsec_crypto_run_both_in.sh | 14 + .../ipsec_crypto/odp_ipsec_crypto_run_both_out.sh | 14 + .../ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh | 13 + .../ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh | 18 + example/ipsec_crypto/odp_ipsec_crypto_run_live.sh | 17 + .../ipsec_crypto/odp_ipsec_crypto_run_router.sh | 9 + .../ipsec_crypto/odp_ipsec_crypto_run_simple.sh | 15 + example/ipsec_crypto/odp_ipsec_fwd_db.c | 173 ++ example/ipsec_crypto/odp_ipsec_fwd_db.h | 98 ++ example/ipsec_crypto/odp_ipsec_misc.h | 343 ++++ example/ipsec_crypto/odp_ipsec_sa_db.c | 328 ++++ example/ipsec_crypto/odp_ipsec_sa_db.h | 131 ++ example/ipsec_crypto/odp_ipsec_sp_db.c | 159 ++ example/ipsec_crypto/odp_ipsec_sp_db.h | 71 + example/ipsec_crypto/odp_ipsec_stream.c | 678 ++++++++ example/ipsec_crypto/odp_ipsec_stream.h | 135 ++ example/m4/configure.m4 | 2 +- platform/linux-generic/test/Makefile.am | 4 +- .../test/ipsec/ipsec_crypto_example.sh | 32 + platform/linux-generic/test/ipsec/ipsec_example.sh | 32 - 63 files changed, 4557 insertions(+), 4554 deletions(-) delete mode 100644 example/ipsec/.gitignore delete mode 100644 example/ipsec/Makefile.am delete mode 100644 example/ipsec/README delete mode 100644 example/ipsec/odp_ipsec.c delete mode 100644 example/ipsec/odp_ipsec_cache.c delete mode 100644 example/ipsec/odp_ipsec_cache.h delete mode 100644 example/ipsec/odp_ipsec_fwd_db.c delete mode 100644 example/ipsec/odp_ipsec_fwd_db.h delete mode 100644 example/ipsec/odp_ipsec_misc.h delete mode 100755 example/ipsec/odp_ipsec_run_ah_in.sh delete mode 100755 example/ipsec/odp_ipsec_run_ah_out.sh delete mode 100755 example/ipsec/odp_ipsec_run_both_in.sh delete mode 100755 example/ipsec/odp_ipsec_run_both_out.sh delete mode 100755 example/ipsec/odp_ipsec_run_esp_in.sh delete mode 100755 example/ipsec/odp_ipsec_run_esp_out.sh delete mode 100755 example/ipsec/odp_ipsec_run_live.sh delete mode 100755 example/ipsec/odp_ipsec_run_router.sh delete mode 100755 example/ipsec/odp_ipsec_run_simple.sh delete mode 100644 example/ipsec/odp_ipsec_sa_db.c delete mode 100644 example/ipsec/odp_ipsec_sa_db.h delete mode 100644 example/ipsec/odp_ipsec_sp_db.c delete mode 100644 example/ipsec/odp_ipsec_sp_db.h delete mode 100644 example/ipsec/odp_ipsec_stream.c delete mode 100644 example/ipsec/odp_ipsec_stream.h create mode 100644 example/ipsec_crypto/.gitignore create mode 100644 example/ipsec_crypto/Makefile.am create mode 100644 example/ipsec_crypto/README create mode 100644 example/ipsec_crypto/odp_ipsec.c create mode 100644 example/ipsec_crypto/odp_ipsec_cache.c create mode 100644 example/ipsec_crypto/odp_ipsec_cache.h create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_live.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_router.sh create mode 100755 example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh create mode 100644 example/ipsec_crypto/odp_ipsec_fwd_db.c create mode 100644 example/ipsec_crypto/odp_ipsec_fwd_db.h create mode 100644 example/ipsec_crypto/odp_ipsec_misc.h create mode 100644 example/ipsec_crypto/odp_ipsec_sa_db.c create mode 100644 example/ipsec_crypto/odp_ipsec_sa_db.h create mode 100644 example/ipsec_crypto/odp_ipsec_sp_db.c create mode 100644 example/ipsec_crypto/odp_ipsec_sp_db.h create mode 100644 example/ipsec_crypto/odp_ipsec_stream.c create mode 100644 example/ipsec_crypto/odp_ipsec_stream.h create mode 100755 platform/linux-generic/test/ipsec/ipsec_crypto_example.sh delete mode 100755 platform/linux-generic/test/ipsec/ipsec_example.sh diff --git a/doc/application-api-guide/examples.dox b/doc/application-api-guide/examples.dox index ba686f295..a45c3127e 100644 --- a/doc/application-api-guide/examples.dox +++ b/doc/application-api-guide/examples.dox @@ -29,16 +29,16 @@ * IPv4 lock-free fragmentation and reassembly example application */ - /** - * @example ipsec/odp_ipsec.c - * IPsec example application using crypto API - */ - /** * @example ipsec_api/odp_ipsec.c * IPsec example application using IPsec API */ + /** + * @example ipsec_crypto/odp_ipsec.c + * IPsec example application using crypto API + */ + /** * @example ipsec_offload/odp_ipsec_offload.c * IPsec offload example application diff --git a/example/Makefile.am b/example/Makefile.am index 174dea6dd..02ef55faf 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -2,8 +2,8 @@ SUBDIRS = classifier \ debug \ generator \ hello \ - ipsec \ ipsec_api \ + ipsec_crypto \ ipsec_offload \ l2fwd_simple \ l3fwd \ diff --git a/example/ipsec/.gitignore b/example/ipsec/.gitignore deleted file mode 100644 index 5b410d31b..000000000 --- a/example/ipsec/.gitignore +++ /dev/null @@ -1 +0,0 @@ -odp_ipsec diff --git a/example/ipsec/Makefile.am b/example/ipsec/Makefile.am deleted file mode 100644 index 1f603750c..000000000 --- a/example/ipsec/Makefile.am +++ /dev/null @@ -1,57 +0,0 @@ -include $(top_srcdir)/example/Makefile.inc - -bin_PROGRAMS = odp_ipsec - -dist_check_SCRIPTS = \ - odp_ipsec_run_ah_in.sh \ - odp_ipsec_run_ah_out.sh \ - odp_ipsec_run_both_in.sh \ - odp_ipsec_run_both_out.sh \ - odp_ipsec_run_esp_in.sh \ - odp_ipsec_run_esp_out.sh \ - odp_ipsec_run_live.sh \ - odp_ipsec_run_router.sh \ - odp_ipsec_run_simple.sh - -odp_ipsec_SOURCES = odp_ipsec.c \ - odp_ipsec_sa_db.c \ - odp_ipsec_sp_db.c \ - odp_ipsec_fwd_db.c \ - odp_ipsec_cache.c \ - odp_ipsec_cache.h \ - odp_ipsec_fwd_db.h \ - odp_ipsec_misc.h \ - odp_ipsec_sa_db.h \ - odp_ipsec_sp_db.h - -if WITH_OPENSSL -odp_ipsec_SOURCES += \ - odp_ipsec_stream.c \ - odp_ipsec_stream.h - -AM_CPPFLAGS = $(OPENSSL_CPPFLAGS) -LDADD += $(OPENSSL_LIBS) - -else -AM_CPPFLAGS = -DNO_OPENSSL -endif - -# If building out-of-tree, make check will not copy the scripts and data to the -# $(builddir) assuming that all commands are run locally. However this prevents -# running tests on a remote target using LOG_COMPILER. -# So copy all script and data files explicitly here. -all-local: - if [ "x$(srcdir)" != "x$(builddir)" ]; then \ - for f in $(dist_check_SCRIPTS); do \ - if [ -e $(srcdir)/$$f ]; then \ - mkdir -p $(builddir)/$$(dirname $$f); \ - cp $(srcdir)/$$f $(builddir)/$$f; \ - fi \ - done \ - fi -clean-local: - if [ "x$(srcdir)" != "x$(builddir)" ]; then \ - for f in $(dist_check_SCRIPTS); do \ - rm -f $(builddir)/$$f; \ - done \ - fi diff --git a/example/ipsec/README b/example/ipsec/README deleted file mode 100644 index da9d6d1f2..000000000 --- a/example/ipsec/README +++ /dev/null @@ -1,169 +0,0 @@ -Copyright (c) 2014-2018, Linaro Limited -All rights reserved. - -SPDX-License-Identifier: BSD-3-Clause - -1. Intro - -The IPsec example application "odp_ipsec" functions as a simple L3 IPv4 router -with support IPsec 3DES cipher and HMAC-MD5 authentication in both the transmit -and receive directions. Note that only IPsec "transport" mode is supported. - -2. Prerequisites - - 2.1 SSL development libraries - -Development has been done to this point with the openssl-devel libraries, -the makefile specifically links with "-lcrypto". - -3. Topology - -The following test topology was used for development. Each of the VMs -is running Fedora 32. Sanity testing consists of pinging VM2 from VM0 -such that the packets traverse VM1. Packets between VM1 and VM2 are -IPsec AH and ESP encapsulated. - - VM0 VM1 (UUT) VM2 -+------------+ +--------------+ +------------+ -| | (clear) | | (crypto) | | -| | subnet | | subnet | | -| p7p1 |<---------------->| p7p1 p8p1 |<---------------->| p7p1 | -| .2 | 192.168.111.0 | .1 .1 | 192.168.222.0 | .2 | -| | | | | | -+------------+ +--------------+ +------------+ - -4. VM configurations - - 4.1 VM0 configuration - -VM0 has the following interface configuration: - - cat /etc/sysconfig/network-scripts/ifcfg-p7p1 - DEVICE=p7p1 - HWADDR=08:00:27:76:B5:E0 - BOOTPROTO=static - IPADDR=192.168.111.2 - NETMASK=255.255.255.0 - ONBOOT=yes - -In addition, static ARP and IPv4 routes must be added on VM0: - - sudo ip route add 192.168.222.0/24 via 192.168.111.1 - sudo arp -s 192.168.111.1 08:00:27:04:BF:8C - - 4.2 VM1 configuration - -For the unit under test, IP forwarding and IP tables were disabled. - -VM1 has the following interface configurations: - - cat /etc/sysconfig/network-scripts/ifcfg-p7p1 - DEVICE=p7p1 - HWADDR=08:00:27:04:BF:8C - BOOTPROTO=static - IPADDR=192.168.111.1 - NETMASK=255.255.255.0 - ONBOOT=yes - - cat /etc/sysconfig/network-scripts/ifcfg-p8p1 - DEVICE=p8p1 - HWADDR=08:00:27:4C:55:CC - BOOTPROTO=static - IPADDR=192.168.222.1 - NETMASK=255.255.255.0 - ONBOOT=yes - -The application is launched on VM1 with the following command: - - sudo ./odp_ipsec -i p7p1,p8p1 \ - -r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ - -r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ - -p 192.168.111.0/24:192.168.222.0/24:out:both \ - -e 192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ - -a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ - -p 192.168.222.0/24:192.168.111.0/24:in:both \ - -e 192.168.222.2:192.168.111.2:3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ - -a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ - -c 2 -m 0 - - 4.3 VM2 configuration - -VM2 has the following interface configuration: - - cat /etc/sysconfig/network-scripts/ifcfg-p7p1 - DEVICE=p7p1 - HWADDR=08:00:27:F5:8B:DB - BOOTPROTO=static - IPADDR=192.168.222.2 - NETMASK=255.255.255.0 - ONBOOT=yes - -In addition, static ARP and IPv4 routes must be added on VM2: - - sudo ip route add 192.168.111.0/24 via 192.168.222.1 - sudo arp -s 192.168.222.1 08:00:27:4c:55:cc - -VM2 must be setup with an IPsec configuration complementing -the configuration used by the "odp_ipsec" application running -on VM1. The configuration is applied using "setkey" (provided by ipsec-tools -package). - -VM2 uses the following setkey configuration: - - cat setkey_vm2.conf - # Flush the SAD and SPD - flush; - spdflush; - - add 192.168.111.2 192.168.222.2 ah 0x200 -A hmac-md5 - 0xa731649644c5dee92cbd9c2e7e188ee6; - add 192.168.222.2 192.168.111.2 ah 0x300 -A hmac-md5 - 0x27f6d123d7077b361662fc6e451f65d8; - - add 192.168.111.2 192.168.222.2 esp 0x201 -E 3des-cbc - 0x656c8523255ccc23a66c1917aa0cf30991fce83532a4b224; - add 192.168.222.2 192.168.111.2 esp 0x301 -E 3des-cbc - 0xc966199f24d095f3990a320d749056401e82b26570320292; - - spdadd 192.168.111.2 192.168.222.2 any -P in ipsec - esp/transport//require - ah/transport//require; - - spdadd 192.168.222.2 192.168.111.2 any -P out ipsec - esp/transport//require - ah/transport//require; - -Apply the setkey configuration: - sudo setkey -f setkey_vm2.conf - -5. Sanity Test with Real Traffic - -Once all three VMs have been configured, static ARP and route entries added, -setkey configuration applied, and odp_ipsec application is running, VM0 should -be able to ping VM2 at the 192.168.222.2 address. - -At VM0 console issue the ping to VM2's address: - - sudo ping -c 2 -i 0.1 192.168.222.2 - PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data. - 64 bytes from 192.168.222.2: icmp_req=1 ttl=64 time=33.9 ms - 64 bytes from 192.168.222.2: icmp_req=2 ttl=64 time=23.3 ms - -At VM2 console use tcpdump to observe IPsec packets: - - sudo tcpdump -nt -i p7p1 - tcpdump: verbose output suppressed, use -v or -vv for full protocol decode - listening on p7p1, link-type EN10MB (Ethernet), capture size 65535 bytes - - IP 192.168.111.2 > 192.168.222.2: AH(spi=0x00000200,seq=0x6): ESP(spi=0x00000201,seq=0x6), length 88 - IP 192.168.222.2 > 192.168.111.2: AH(spi=0x00000300,seq=0x7a): ESP(spi=0x00000301,seq=0x7a), length 88 - IP 192.168.111.2 > 192.168.222.2: AH(spi=0x00000200,seq=0x7): ESP(spi=0x00000201,seq=0x7), length 88 - IP 192.168.222.2 > 192.168.111.2: AH(spi=0x00000300,seq=0x7b): ESP(spi=0x00000301,seq=0x7b), length 88 - -6. Standalone Loopback Tests - -BASH batch files are now included to run several simple loopback tests that -do not require any packet IO. The scripts create internal "loopback" packet -interfaces. -Before running the example bash scripts add odp_ipsec to your PATH -export PATH=":$PATH" diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c deleted file mode 100644 index c4f34cbfa..000000000 --- a/example/ipsec/odp_ipsec.c +++ /dev/null @@ -1,1658 +0,0 @@ -/* Copyright (c) 2013-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/** - * @file - * - * @example odp_example_ipsec.c ODP basic packet IO cross connect with IPsec test application - */ - -/* enable strtok */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifndef NO_OPENSSL -#include -#else -static void init_stream_db(void) {} -static void resolve_stream_db(void) {} -static int create_stream_db_inputs(void) -{ - return 0; -} - -static odp_bool_t verify_stream_db_outputs(void) -{ - return true; -} - -static int create_stream_db_entry(char *input ODP_UNUSED) -{ - return -1; -} -#endif - -/* maximum number of worker threads */ -#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1) - -#define MAX_POLL_QUEUES 256 - -/** - * Parsed command line application arguments - */ -typedef struct { - unsigned int cpu_count; - int if_count; /**< Number of interfaces to be used */ - char **if_names; /**< Array of pointers to interface names */ - crypto_api_mode_e mode; /**< Crypto API preferred mode */ - odp_pool_t pool; /**< Buffer pool for packet IO */ - char *if_str; /**< Storage for interface names */ -} appl_args_t; - -/** - * Grouping of both parsed CL args and global application data - */ -typedef struct { - /** Application (parsed) arguments */ - appl_args_t appl; - odp_shm_t shm; - odp_pool_t ctx_pool; - odp_pool_t out_pool; - odp_pool_t pkt_pool; - /** ATOMIC queue for IPsec sequence number assignment */ - odp_queue_t seqnumq; - /** ORDERED queue for per packet crypto API completion events */ - odp_queue_t completionq; - /** Synchronize threads before packet processing begins */ - odp_barrier_t sync_barrier; - odp_queue_t poll_queues[MAX_POLL_QUEUES]; - int num_polled_queues; - /* Stop workers if set to 1 */ - odp_atomic_u32_t exit_threads; -} global_data_t; - -/* helper funcs */ -static void parse_args(int argc, char *argv[], appl_args_t *appl_args); -static void print_info(char *progname, appl_args_t *appl_args); -static void usage(char *progname); - -/** - * Buffer pool for packet IO - */ -#define SHM_PKT_POOL_BUF_COUNT 1024 -#define SHM_PKT_POOL_BUF_SIZE 4096 -#define SHM_PKT_POOL_SIZE (SHM_PKT_POOL_BUF_COUNT * SHM_PKT_POOL_BUF_SIZE) - -/** - * Buffer pool for crypto session output packets - */ -#define SHM_OUT_POOL_BUF_COUNT 1024 -#define SHM_OUT_POOL_BUF_SIZE 4096 -#define SHM_OUT_POOL_SIZE (SHM_OUT_POOL_BUF_COUNT * SHM_OUT_POOL_BUF_SIZE) - -/** - * Packet processing states/steps - */ -typedef enum { - PKT_STATE_INPUT_VERIFY, /**< Verify IPv4 and ETH */ - PKT_STATE_IPSEC_IN_CLASSIFY, /**< Initiate input IPsec */ - PKT_STATE_IPSEC_IN_FINISH, /**< Finish input IPsec */ - PKT_STATE_ROUTE_LOOKUP, /**< Use DST IP to find output IF */ - PKT_STATE_IPSEC_OUT_CLASSIFY, /**< Intiate output IPsec */ - PKT_STATE_IPSEC_OUT_SEQ, /**< Assign IPsec sequence numbers */ - PKT_STATE_IPSEC_OUT_FINISH, /**< Finish output IPsec */ - PKT_STATE_TRANSMIT, /**< Send packet to output IF queue */ -} pkt_state_e; - -/** - * Packet processing result codes - */ -typedef enum { - PKT_CONTINUE, /**< No events posted, keep processing */ - PKT_POSTED, /**< Event posted, stop processing */ - PKT_DROP, /**< Reason to drop detected, stop processing */ - PKT_DONE /**< Finished with packet, stop processing */ -} pkt_disposition_e; - -/** - * Per packet IPsec processing context - */ -typedef struct { - uint8_t ip_tos; /**< Saved IP TOS value */ - uint16_t ip_frag_offset; /**< Saved IP flags value */ - uint8_t ip_ttl; /**< Saved IP TTL value */ - int hdr_len; /**< Length of IPsec headers */ - int trl_len; /**< Length of IPsec trailers */ - uint16_t tun_hdr_offset; /**< Offset of tunnel header from - buffer start */ - uint16_t ah_offset; /**< Offset of AH header from buffer start */ - uint16_t esp_offset; /**< Offset of ESP header from buffer start */ - - /* Input only */ - uint32_t src_ip; /**< SA source IP address */ - uint32_t dst_ip; /**< SA dest IP address */ - - /* Output only */ - odp_crypto_packet_op_param_t params; /**< Parameters for crypto call */ - uint32_t *ah_seq; /**< AH sequence number location */ - uint32_t *esp_seq; /**< ESP sequence number location */ - uint16_t *tun_hdr_id; /**< Tunnel header ID > */ -} ipsec_ctx_t; - -/** - * Per packet processing context - */ -typedef struct { - odp_buffer_t buffer; /**< Buffer for context */ - pkt_state_e state; /**< Next processing step */ - ipsec_ctx_t ipsec; /**< IPsec specific context */ - odp_pktout_queue_t pktout; /**< Packet output queue */ -} pkt_ctx_t; - -#define SHM_CTX_POOL_BUF_SIZE (sizeof(pkt_ctx_t)) -#define SHM_CTX_POOL_BUF_COUNT (SHM_PKT_POOL_BUF_COUNT + SHM_OUT_POOL_BUF_COUNT) -#define SHM_CTX_POOL_SIZE (SHM_CTX_POOL_BUF_COUNT * SHM_CTX_POOL_BUF_SIZE) - -static global_data_t *global; - -static void sig_handler(int signo ODP_UNUSED) -{ - if (global == NULL) - return; - odp_atomic_store_u32(&global->exit_threads, 1); -} - -/** - * Get per packet processing context from packet buffer - * - * @param pkt Packet - * - * @return pointer to context area - */ -static -pkt_ctx_t *get_pkt_ctx_from_pkt(odp_packet_t pkt) -{ - return (pkt_ctx_t *)odp_packet_user_ptr(pkt); -} - -/** - * Allocate per packet processing context and associate it with - * packet buffer - * - * @param pkt Packet - * - * @return pointer to context area - */ -static -pkt_ctx_t *alloc_pkt_ctx(odp_packet_t pkt) -{ - odp_buffer_t ctx_buf = odp_buffer_alloc(global->ctx_pool); - pkt_ctx_t *ctx; - - if (odp_unlikely(ODP_BUFFER_INVALID == ctx_buf)) - return NULL; - - ctx = odp_buffer_addr(ctx_buf); - memset(ctx, 0, sizeof(*ctx)); - ctx->buffer = ctx_buf; - odp_packet_user_ptr_set(pkt, ctx); - - return ctx; -} - -/** - * Release per packet resources - * - * @param ctx Packet context - */ -static -void free_pkt_ctx(pkt_ctx_t *ctx) -{ - odp_buffer_free(ctx->buffer); -} - -/** - * Example supports either polling queues or using odp_schedule - */ -typedef odp_queue_t (*queue_create_func_t) - (const char *, const odp_queue_param_t *); -typedef odp_event_t (*schedule_func_t) (odp_queue_t *); - -static queue_create_func_t queue_create; -static schedule_func_t schedule_fn; - -/** - * odp_queue_create wrapper to enable polling versus scheduling - */ -static -odp_queue_t polled_odp_queue_create(const char *name, - const odp_queue_param_t *param) -{ - odp_queue_t my_queue; - odp_queue_param_t qp; - odp_queue_type_t type; - - odp_queue_param_init(&qp); - if (param) - memcpy(&qp, param, sizeof(odp_queue_param_t)); - - type = qp.type; - - if (ODP_QUEUE_TYPE_SCHED == type) { - printf("%s: change %s to PLAIN\n", __func__, name); - qp.type = ODP_QUEUE_TYPE_PLAIN; - } - - my_queue = odp_queue_create(name, &qp); - - if (ODP_QUEUE_TYPE_SCHED == type) { - global->poll_queues[global->num_polled_queues++] = my_queue; - printf("%s: adding %"PRIu64"\n", __func__, - odp_queue_to_u64(my_queue)); - } - - return my_queue; -} - -static inline -odp_event_t odp_schedule_cb(odp_queue_t *from) -{ - return odp_schedule(from, ODP_SCHED_NO_WAIT); -} - -/** - * odp_schedule replacement to poll queues versus using ODP scheduler - */ -static -odp_event_t polled_odp_schedule_cb(odp_queue_t *from) -{ - int idx = 0; - - while (idx < global->num_polled_queues) { - odp_queue_t queue = global->poll_queues[idx++]; - odp_event_t ev; - - ev = odp_queue_deq(queue); - - if (ODP_EVENT_INVALID != ev) { - *from = queue; - return ev; - } - } - - *from = ODP_QUEUE_INVALID; - return ODP_EVENT_INVALID; -} - -/** - * IPsec pre argument processing intialization - */ -static -void ipsec_init_pre(void) -{ - odp_queue_param_t qparam; - odp_pool_param_t params; - - /* - * Create queues - * - * - completion queue (should eventually be ORDERED) - * - sequence number queue (must be ATOMIC) - */ - odp_queue_param_init(&qparam); - qparam.type = ODP_QUEUE_TYPE_SCHED; - qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; - qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; - qparam.sched.group = ODP_SCHED_GROUP_ALL; - - global->completionq = queue_create("completion", &qparam); - if (ODP_QUEUE_INVALID == global->completionq) { - ODPH_ERR("Error: completion queue creation failed\n"); - exit(EXIT_FAILURE); - } - - qparam.type = ODP_QUEUE_TYPE_SCHED; - qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; - qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; - qparam.sched.group = ODP_SCHED_GROUP_ALL; - - global->seqnumq = queue_create("seqnum", &qparam); - if (ODP_QUEUE_INVALID == global->seqnumq) { - ODPH_ERR("Error: sequence number queue creation failed\n"); - exit(EXIT_FAILURE); - } - - /* Create output buffer pool */ - odp_pool_param_init(¶ms); - params.pkt.seg_len = SHM_OUT_POOL_BUF_SIZE; - params.pkt.len = SHM_OUT_POOL_BUF_SIZE; - params.pkt.num = SHM_PKT_POOL_BUF_COUNT; - params.type = ODP_POOL_PACKET; - - global->out_pool = odp_pool_create("out_pool", ¶ms); - - if (ODP_POOL_INVALID == global->out_pool) { - ODPH_ERR("Error: message pool create failed.\n"); - exit(EXIT_FAILURE); - } - - /* Initialize our data bases */ - init_sp_db(); - init_sa_db(); - init_tun_db(); - init_ipsec_cache(); -} - -/** - * IPsec post argument processing intialization - * - * Resolve SP DB with SA DB and create corresponding IPsec cache entries - * - * @param api_mode Mode to use when invoking per packet crypto API - */ -static -void ipsec_init_post(crypto_api_mode_e api_mode) -{ - sp_db_entry_t *entry; - - /* Attempt to find appropriate SA for each SP */ - for (entry = sp_db->list; NULL != entry; entry = entry->next) { - sa_db_entry_t *cipher_sa = NULL; - sa_db_entry_t *auth_sa = NULL; - tun_db_entry_t *tun = NULL; - - if (entry->esp) { - cipher_sa = find_sa_db_entry(&entry->src_subnet, - &entry->dst_subnet, - 1); - tun = find_tun_db_entry(cipher_sa->src_ip, - cipher_sa->dst_ip); - } - if (entry->ah) { - auth_sa = find_sa_db_entry(&entry->src_subnet, - &entry->dst_subnet, - 0); - tun = find_tun_db_entry(auth_sa->src_ip, - auth_sa->dst_ip); - } - - if (cipher_sa || auth_sa) { - if (create_ipsec_cache_entry(cipher_sa, - auth_sa, - tun, - api_mode, - entry->input, - global->completionq, - global->out_pool)) { - ODPH_ERR("Error: IPSec cache entry failed.\n" - ); - exit(EXIT_FAILURE); - } - } else { - printf(" WARNING: SA not found for SP\n"); - dump_sp_db_entry(entry); - } - } -} - -#ifndef NO_OPENSSL -static -int check_stream_db_out(const char *intf) -{ - 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) { - if (!strcmp(stream->output.intf, intf)) - return 1; - } - - return 0; -} -#else -static -int check_stream_db_out(const char *intf ODP_UNUSED) -{ - return 0; -} -#endif - -/** - * Initialize interface - * - * Initialize ODP pktio and queues, query MAC address and update - * forwarding database. - * - * @param intf Interface name string - */ -static -void initialize_intf(char *intf) -{ - odp_pktio_t pktio; - odp_pktout_queue_t pktout; - odp_queue_t inq; - int ret; - uint8_t src_mac[ODPH_ETHADDR_LEN]; - char src_mac_str[MAX_STRING]; - odp_pktio_param_t pktio_param; - odp_pktin_queue_param_t pktin_param; - - odp_pktio_param_init(&pktio_param); - - if (getenv("ODP_IPSEC_USE_POLL_QUEUES") || - check_stream_db_out(intf)) - pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE; - else - pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; - - /* - * Open a packet IO instance for thread and get default output queue - */ - pktio = odp_pktio_open(intf, global->pkt_pool, &pktio_param); - if (ODP_PKTIO_INVALID == pktio) { - ODPH_ERR("Error: pktio create failed for %s\n", intf); - exit(EXIT_FAILURE); - } - - odp_pktin_queue_param_init(&pktin_param); - pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC; - - if (odp_pktin_queue_config(pktio, &pktin_param)) { - ODPH_ERR("Error: pktin config failed for %s\n", intf); - exit(EXIT_FAILURE); - } - - if (odp_pktout_queue_config(pktio, NULL)) { - ODPH_ERR("Error: pktout config failed for %s\n", intf); - exit(EXIT_FAILURE); - } - - if (odp_pktin_event_queue(pktio, &inq, 1) != 1) { - ODPH_ERR("Error: failed to get input queue for %s\n", intf); - exit(EXIT_FAILURE); - } - - if (odp_pktout_queue(pktio, &pktout, 1) != 1) { - ODPH_ERR("Error: failed to get pktout queue for %s\n", intf); - exit(EXIT_FAILURE); - } - - ret = odp_pktio_start(pktio); - if (ret) { - ODPH_ERR("Error: unable to start %s\n", intf); - exit(EXIT_FAILURE); - } - - /* Read the source MAC address for this interface */ - ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac)); - if (ret <= 0) { - ODPH_ERR("Error: failed during MAC address get for %s\n", intf); - exit(EXIT_FAILURE); - } - - printf("Created pktio:%02" PRIu64 ", queue mode (ATOMIC queues)\n" - " default pktio%02" PRIu64 "-INPUT queue:%" PRIu64 "\n" - " source mac address %s\n", - odp_pktio_to_u64(pktio), odp_pktio_to_u64(pktio), - odp_queue_to_u64(inq), - mac_addr_str(src_mac_str, src_mac)); - - /* Resolve any routes using this interface for output */ - resolve_fwd_db(intf, pktio, pktout, src_mac); -} - -/** - * Packet Processing - Input verification - * - * @param pkt Packet to inspect - * @param ctx Packet process context (not used) - * - * @return PKT_CONTINUE if good, supported packet else PKT_DROP - */ -static -pkt_disposition_e do_input_verify(odp_packet_t pkt, - pkt_ctx_t *ctx ODP_UNUSED) -{ - if (odp_unlikely(odp_packet_has_error(pkt))) - return PKT_DROP; - - if (!odp_packet_has_eth(pkt)) - return PKT_DROP; - - if (!odp_packet_has_ipv4(pkt)) - return PKT_DROP; - - return PKT_CONTINUE; -} - -/** - * Packet Processing - Route lookup in forwarding database - * - * @param pkt Packet to route - * @param ctx Packet process context - * - * @return PKT_CONTINUE if route found else PKT_DROP - */ -static -pkt_disposition_e do_route_fwd_db(odp_packet_t pkt, pkt_ctx_t *ctx) -{ - odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); - fwd_db_entry_t *entry; - - entry = find_fwd_db_entry(odp_be_to_cpu_32(ip->dst_addr)); - - if (entry) { - odph_ethhdr_t *eth = - (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL); - - memcpy(ð->dst, entry->dst_mac, ODPH_ETHADDR_LEN); - memcpy(ð->src, entry->src_mac, ODPH_ETHADDR_LEN); - ctx->pktout = entry->pktout; - - return PKT_CONTINUE; - } - - return PKT_DROP; -} - -/** - * Packet Processing - Input IPsec packet classification - * - * Verify the received packet has IPsec headers and a match - * in the IPsec cache, if so issue crypto request else skip - * input crypto. - * - * @param pkt Packet to classify - * @param ctx Packet process context - * @param skip Pointer to return "skip" indication - * - * @return PKT_CONTINUE if done else PKT_POSTED - */ -static -pkt_disposition_e do_ipsec_in_classify(odp_packet_t *pkt, - pkt_ctx_t *ctx, - odp_bool_t *skip) -{ - uint8_t *buf = odp_packet_data(*pkt); - odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*pkt, NULL); - int hdr_len; - odph_ahhdr_t *ah = NULL; - odph_esphdr_t *esp = NULL; - ipsec_cache_entry_t *entry; - odp_crypto_packet_op_param_t params; - odp_packet_t out_pkt; - - /* Default to skip IPsec */ - *skip = TRUE; - - /* Check IP header for IPSec protocols and look it up */ - hdr_len = locate_ipsec_headers(ip, &ah, &esp); - if (!ah && !esp) - return PKT_CONTINUE; - entry = find_ipsec_cache_entry_in(odp_be_to_cpu_32(ip->src_addr), - odp_be_to_cpu_32(ip->dst_addr), - ah, - esp); - if (!entry) - return PKT_CONTINUE; - - /* Account for configured ESP IV length in packet */ - hdr_len += entry->esp.iv_len; - - /* Initialize parameters block */ - memset(¶ms, 0, sizeof(params)); - params.session = entry->state.session; - out_pkt = entry->in_place ? *pkt : ODP_PACKET_INVALID; - - /*Save everything to context */ - ctx->ipsec.ip_tos = ip->tos; - ctx->ipsec.ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset); - ctx->ipsec.ip_ttl = ip->ttl; - ctx->ipsec.ah_offset = ah ? ((uint8_t *)ah) - buf : 0; - ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0; - ctx->ipsec.hdr_len = hdr_len; - ctx->ipsec.trl_len = 0; - ctx->ipsec.src_ip = entry->src_ip; - ctx->ipsec.dst_ip = entry->dst_ip; - - /*If authenticating, zero the mutable fields build the request */ - if (ah) { - ip->chksum = 0; - ip->tos = 0; - ip->frag_offset = 0; - ip->ttl = 0; - - params.auth_range.offset = ((uint8_t *)ip) - buf; - params.auth_range.length = odp_be_to_cpu_16(ip->tot_len); - params.hash_result_offset = ah->icv - buf; - } - - /* If deciphering build request */ - if (esp) { - params.cipher_range.offset = ipv4_data_p(ip) + hdr_len - buf; - params.cipher_range.length = ipv4_data_len(ip) - hdr_len; - params.cipher_iv_ptr = esp->iv; - } - - /* Issue crypto request */ - *skip = FALSE; - ctx->state = PKT_STATE_IPSEC_IN_FINISH; - if (entry->async) { - if (odp_crypto_op_enq(pkt, &out_pkt, ¶ms, 1) != 1) { - ODPH_ERR("Error: odp_crypto_op_enq() failed\n"); - exit(EXIT_FAILURE); - } - return PKT_POSTED; - } - - if (odp_crypto_op(pkt, &out_pkt, ¶ms, 1) != 1) { - ODPH_ERR("Error: odp_crypto_op() failed\n"); - exit(EXIT_FAILURE); - } - *pkt = out_pkt; - - return PKT_CONTINUE; -} - -/** - * Packet Processing - Input IPsec packet processing cleanup - * - * @param pkt Packet to handle - * @param ctx Packet process context - * - * @return PKT_CONTINUE if successful else PKT_DROP - */ -static -pkt_disposition_e do_ipsec_in_finish(odp_packet_t pkt, - pkt_ctx_t *ctx) -{ - odph_ipv4hdr_t *ip; - odp_crypto_packet_result_t result; - int hdr_len = ctx->ipsec.hdr_len; - int trl_len = 0; - - odp_crypto_result(&result, pkt); - - /* Check crypto result */ - if (!result.ok) { - if (!is_crypto_op_status_ok(&result.cipher_status)) - return PKT_DROP; - if (!is_crypto_op_status_ok(&result.auth_status)) - return PKT_DROP; - } - ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); - - /* - * Finish auth - */ - if (ctx->ipsec.ah_offset) { - uint8_t *buf = odp_packet_data(pkt); - odph_ahhdr_t *ah; - - ah = (odph_ahhdr_t *)(ctx->ipsec.ah_offset + buf); - ip->proto = ah->next_header; - } - - /* - * Finish cipher by finding ESP trailer and processing - * - * NOTE: ESP authentication ICV not supported - */ - if (ctx->ipsec.esp_offset) { - uint8_t *eop = (uint8_t *)(ip) + odp_be_to_cpu_16(ip->tot_len); - odph_esptrl_t *esp_t = (odph_esptrl_t *)(eop) - 1; - - ip->proto = esp_t->next_header; - trl_len += esp_t->pad_len + sizeof(*esp_t); - } - - /* We have a tunneled IPv4 packet */ - if (ip->proto == ODPH_IPV4) { - odp_packet_pull_head(pkt, sizeof(*ip) + hdr_len); - odp_packet_pull_tail(pkt, trl_len); - odph_ethhdr_t *eth; - - eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL); - eth->type = ODPH_ETHTYPE_IPV4; - ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); - - /* Check inbound policy */ - if ((ip->src_addr != ctx->ipsec.src_ip || - ip->dst_addr != ctx->ipsec.dst_ip)) - return PKT_DROP; - - return PKT_CONTINUE; - } - - /* Finalize the IPv4 header */ - ipv4_adjust_len(ip, -(hdr_len + trl_len)); - ip->ttl = ctx->ipsec.ip_ttl; - ip->tos = ctx->ipsec.ip_tos; - ip->frag_offset = odp_cpu_to_be_16(ctx->ipsec.ip_frag_offset); - ip->chksum = 0; - odph_ipv4_csum_update(pkt); - - /* Correct the packet length and move payload into position */ - memmove(ipv4_data_p(ip), - ipv4_data_p(ip) + hdr_len, - odp_be_to_cpu_16(ip->tot_len)); - odp_packet_pull_tail(pkt, hdr_len + trl_len); - - /* Fall through to next state */ - return PKT_CONTINUE; -} - -/** - * Packet Processing - Output IPsec packet classification - * - * Verify the outbound packet has a match in the IPsec cache, - * if so issue prepend IPsec headers and prepare parameters - * for crypto API call. Post the packet to ATOMIC queue so - * that sequence numbers can be applied in packet order as - * the next processing step. - * - * @param pkt Packet to classify - * @param ctx Packet process context - * @param skip Pointer to return "skip" indication - * - * @return PKT_CONTINUE if done else PKT_POSTED - */ -static -pkt_disposition_e do_ipsec_out_classify(odp_packet_t pkt, - pkt_ctx_t *ctx, - odp_bool_t *skip) -{ - uint8_t *buf = odp_packet_data(pkt); - odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); - uint16_t ip_data_len = ipv4_data_len(ip); - uint8_t *ip_data = ipv4_data_p(ip); - ipsec_cache_entry_t *entry; - odp_crypto_packet_op_param_t params; - int hdr_len = 0; - int trl_len = 0; - odph_ahhdr_t *ah = NULL; - odph_esphdr_t *esp = NULL; - - /* Default to skip IPsec */ - *skip = TRUE; - - /* Find record */ - entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr), - odp_be_to_cpu_32(ip->dst_addr), - ip->proto); - if (!entry) - return PKT_CONTINUE; - - /* Save IPv4 stuff */ - ctx->ipsec.ip_tos = ip->tos; - ctx->ipsec.ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset); - ctx->ipsec.ip_ttl = ip->ttl; - - /* Initialize parameters block */ - memset(¶ms, 0, sizeof(params)); - params.session = entry->state.session; - - if (entry->mode == IPSEC_SA_MODE_TUNNEL) { - hdr_len += sizeof(odph_ipv4hdr_t); - ip_data = (uint8_t *)ip; - ip_data_len += sizeof(odph_ipv4hdr_t); - } - /* Compute ah and esp, determine length of headers, move the data */ - if (entry->ah.alg) { - ah = (odph_ahhdr_t *)(ip_data + hdr_len); - hdr_len += sizeof(odph_ahhdr_t); - hdr_len += entry->ah.icv_len; - } - if (entry->esp.alg) { - esp = (odph_esphdr_t *)(ip_data + hdr_len); - hdr_len += sizeof(odph_esphdr_t); - hdr_len += entry->esp.iv_len; - } - memmove(ip_data + hdr_len, ip_data, ip_data_len); - ip_data += hdr_len; - - /* update outer header in tunnel mode */ - if (entry->mode == IPSEC_SA_MODE_TUNNEL) { - /* tunnel addresses */ - ip->src_addr = odp_cpu_to_be_32(entry->tun_src_ip); - ip->dst_addr = odp_cpu_to_be_32(entry->tun_dst_ip); - } - - /* For cipher, compute encrypt length, build headers and request */ - if (esp) { - uint32_t encrypt_len; - odph_esptrl_t *esp_t; - - encrypt_len = ESP_ENCODE_LEN(ip_data_len + - sizeof(*esp_t), - entry->esp.block_len); - trl_len = encrypt_len - ip_data_len; - - esp->spi = odp_cpu_to_be_32(entry->esp.spi); - memcpy(esp + 1, entry->state.iv, entry->esp.iv_len); - - esp_t = (odph_esptrl_t *)(ip_data + encrypt_len) - 1; - esp_t->pad_len = trl_len - sizeof(*esp_t); - if (entry->mode == IPSEC_SA_MODE_TUNNEL) - esp_t->next_header = ODPH_IPV4; - else - esp_t->next_header = ip->proto; - ip->proto = ODPH_IPPROTO_ESP; - - params.cipher_range.offset = ip_data - buf; - params.cipher_range.length = encrypt_len; - } - - /* For authentication, build header clear mutables and build request */ - if (ah) { - memset(ah, 0, sizeof(*ah) + entry->ah.icv_len); - ah->spi = odp_cpu_to_be_32(entry->ah.spi); - ah->ah_len = 1 + (entry->ah.icv_len / 4); - if (entry->mode == IPSEC_SA_MODE_TUNNEL && !esp) - ah->next_header = ODPH_IPV4; - else - ah->next_header = ip->proto; - ip->proto = ODPH_IPPROTO_AH; - - ip->chksum = 0; - ip->tos = 0; - ip->frag_offset = 0; - ip->ttl = 0; - - params.auth_range.offset = ((uint8_t *)ip) - buf; - params.auth_range.length = - odp_be_to_cpu_16(ip->tot_len) + (hdr_len + trl_len); - params.hash_result_offset = ah->icv - buf; - } - - /* Set IPv4 length before authentication */ - ipv4_adjust_len(ip, hdr_len + trl_len); - if (!odp_packet_push_tail(pkt, hdr_len + trl_len)) - return PKT_DROP; - - /* Save remaining context */ - ctx->ipsec.hdr_len = hdr_len; - ctx->ipsec.trl_len = trl_len; - ctx->ipsec.ah_offset = ah ? ((uint8_t *)ah) - buf : 0; - ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0; - ctx->ipsec.tun_hdr_offset = (entry->mode == IPSEC_SA_MODE_TUNNEL) ? - ((uint8_t *)ip - buf) : 0; - ctx->ipsec.ah_seq = &entry->state.ah_seq; - ctx->ipsec.esp_seq = &entry->state.esp_seq; - ctx->ipsec.tun_hdr_id = &entry->state.tun_hdr_id; - memcpy(&ctx->ipsec.params, ¶ms, sizeof(params)); - - *skip = FALSE; - - return PKT_POSTED; -} - -/** - * Packet Processing - Output IPsec packet sequence number assignment - * - * Assign the necessary sequence numbers and then issue the crypto API call - * - * @param pkt Packet to handle - * @param ctx Packet process context - * - * @return PKT_CONTINUE if done else PKT_POSTED - */ -static -pkt_disposition_e do_ipsec_out_seq(odp_packet_t *pkt, - pkt_ctx_t *ctx) -{ - uint8_t *buf = odp_packet_data(*pkt); - odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*pkt, NULL); - odp_packet_t out_pkt; - ipsec_cache_entry_t *entry; - - entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr), - odp_be_to_cpu_32(ip->dst_addr), - ip->proto); - if (!entry) - return PKT_DROP; - - /* We were dispatched from atomic queue, assign sequence numbers */ - if (ctx->ipsec.ah_offset) { - odph_ahhdr_t *ah; - - ah = (odph_ahhdr_t *)(ctx->ipsec.ah_offset + buf); - ah->seq_no = odp_cpu_to_be_32((*ctx->ipsec.ah_seq)++); - } - if (ctx->ipsec.esp_offset) { - odph_esphdr_t *esp; - - esp = (odph_esphdr_t *)(ctx->ipsec.esp_offset + buf); - esp->seq_no = odp_cpu_to_be_32((*ctx->ipsec.esp_seq)++); - } - if (ctx->ipsec.tun_hdr_offset) { - odph_ipv4hdr_t *ip; - int ret; - - ip = (odph_ipv4hdr_t *)(ctx->ipsec.tun_hdr_offset + buf); - ip->id = odp_cpu_to_be_16((*ctx->ipsec.tun_hdr_id)++); - if (!ip->id) { - /* re-init tunnel hdr id */ - ret = odp_random_data((uint8_t *)ctx->ipsec.tun_hdr_id, - sizeof(*ctx->ipsec.tun_hdr_id), - 1); - if (ret != sizeof(*ctx->ipsec.tun_hdr_id)) { - ODPH_ERR("Error: Not enough random data\n"); - exit(EXIT_FAILURE); - } - } - } - - out_pkt = entry->in_place ? *pkt : ODP_PACKET_INVALID; - - /* Issue crypto request */ - if (entry->async) { - if (odp_crypto_op_enq(pkt, &out_pkt, - &ctx->ipsec.params, 1) != 1) { - ODPH_ERR("Error: odp_crypto_op_enq() failed\n"); - exit(EXIT_FAILURE); - } - return PKT_POSTED; - } - - if (odp_crypto_op(pkt, &out_pkt, &ctx->ipsec.params, 1) != 1) { - ODPH_ERR("Error: odp_crypto_op() failed\n"); - exit(EXIT_FAILURE); - } - *pkt = out_pkt; - - return PKT_CONTINUE; -} - -/** - * Packet Processing - Output IPsec packet processing cleanup - * - * @param pkt Packet to handle - * @param ctx Packet process context - * - * @return PKT_CONTINUE if successful else PKT_DROP - */ -static -pkt_disposition_e do_ipsec_out_finish(odp_packet_t pkt, - pkt_ctx_t *ctx) -{ - odph_ipv4hdr_t *ip; - odp_crypto_packet_result_t result; - - odp_crypto_result(&result, pkt); - - /* Check crypto result */ - if (!result.ok) { - if (!is_crypto_op_status_ok(&result.cipher_status)) - return PKT_DROP; - if (!is_crypto_op_status_ok(&result.auth_status)) - return PKT_DROP; - } - ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); - - /* Finalize the IPv4 header */ - ip->ttl = ctx->ipsec.ip_ttl; - ip->tos = ctx->ipsec.ip_tos; - ip->frag_offset = odp_cpu_to_be_16(ctx->ipsec.ip_frag_offset); - ip->chksum = 0; - odph_ipv4_csum_update(pkt); - - /* Fall through to next state */ - return PKT_CONTINUE; -} - -/** - * Packet IO worker thread - * - * Loop calling odp_schedule to obtain packets from one of three sources, - * and continue processing the packet based on the state stored in its - * per packet context. - * - * - Input interfaces (i.e. new work) - * - Sequence number assignment queue - * - Per packet crypto API completion queue - * - * @param arg Required by "odph_odpthreads_create", unused - * - * @return NULL (should never return) - */ -static -int pktio_thread(void *arg ODP_UNUSED) -{ - int thr; - odp_packet_t pkt; - odp_event_t ev; - unsigned long pkt_cnt = 0; - - thr = odp_thread_id(); - - printf("Pktio thread [%02i] starts\n", thr); - - odp_barrier_wait(&global->sync_barrier); - - /* Loop packets */ - while (!odp_atomic_load_u32(&global->exit_threads)) { - pkt_disposition_e rc; - pkt_ctx_t *ctx; - odp_queue_t dispatchq; - odp_event_subtype_t subtype; - - /* Use schedule to get event from any input queue */ - ev = schedule_fn(&dispatchq); - - if (ev == ODP_EVENT_INVALID) - continue; - - /* Determine new work versus completion or sequence number */ - if (ODP_EVENT_PACKET == odp_event_types(ev, &subtype)) { - pkt = odp_packet_from_event(ev); - if (global->seqnumq == dispatchq || - global->completionq == dispatchq) { - ctx = get_pkt_ctx_from_pkt(pkt); - } else { - ctx = alloc_pkt_ctx(pkt); - if (!ctx) { - odp_packet_free(pkt); - continue; - } - ctx->state = PKT_STATE_INPUT_VERIFY; - } - } else { - ODPH_ERR("Error: Bad event type\n"); - exit(EXIT_FAILURE); - } - - /* - * We now have a packet and its associated context. Loop here - * executing processing based on the current state value stored - * in the context as long as the processing return code - * indicates PKT_CONTINUE. - * - * For other return codes: - * - * o PKT_DONE - finished with the packet - * o PKT_DROP - something incorrect about the packet, drop it - * o PKT_POSTED - packet/event has been queued for later - */ - do { - odp_bool_t skip = FALSE; - - switch (ctx->state) { - case PKT_STATE_INPUT_VERIFY: - - rc = do_input_verify(pkt, ctx); - ctx->state = PKT_STATE_IPSEC_IN_CLASSIFY; - break; - - case PKT_STATE_IPSEC_IN_CLASSIFY: - - ctx->state = PKT_STATE_ROUTE_LOOKUP; - rc = do_ipsec_in_classify(&pkt, - ctx, - &skip); - break; - - case PKT_STATE_IPSEC_IN_FINISH: - - rc = do_ipsec_in_finish(pkt, ctx); - ctx->state = PKT_STATE_ROUTE_LOOKUP; - break; - - case PKT_STATE_ROUTE_LOOKUP: - - rc = do_route_fwd_db(pkt, ctx); - ctx->state = PKT_STATE_IPSEC_OUT_CLASSIFY; - break; - - case PKT_STATE_IPSEC_OUT_CLASSIFY: - - rc = do_ipsec_out_classify(pkt, - ctx, - &skip); - if (odp_unlikely(skip)) { - ctx->state = PKT_STATE_TRANSMIT; - } else { - ctx->state = PKT_STATE_IPSEC_OUT_SEQ; - if (odp_queue_enq(global->seqnumq, ev)) - rc = PKT_DROP; - } - break; - - case PKT_STATE_IPSEC_OUT_SEQ: - - ctx->state = PKT_STATE_IPSEC_OUT_FINISH; - rc = do_ipsec_out_seq(&pkt, ctx); - break; - - case PKT_STATE_IPSEC_OUT_FINISH: - - rc = do_ipsec_out_finish(pkt, ctx); - ctx->state = PKT_STATE_TRANSMIT; - break; - - case PKT_STATE_TRANSMIT: - - if (odp_pktout_send(ctx->pktout, &pkt, 1) < 1) { - rc = PKT_DROP; - } else { - rc = PKT_DONE; - } - break; - - default: - rc = PKT_DROP; - break; - } - } while (PKT_CONTINUE == rc); - - /* Free context on drop or transmit */ - if ((PKT_DROP == rc) || (PKT_DONE == rc)) - free_pkt_ctx(ctx); - - - /* Check for drop */ - if (PKT_DROP == rc) - odp_packet_free(pkt); - - /* Print packet counts every once in a while */ - if (PKT_DONE == rc) { - if (odp_unlikely(pkt_cnt++ % 1000 == 0)) { - printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); - fflush(NULL); - } - } - } - - return 0; -} - -/** - * ODP ipsec example main function - */ -int -main(int argc, char *argv[]) -{ - odph_helper_options_t helper_options; - odph_odpthread_t thread_tbl[MAX_WORKERS]; - int num_workers; - int i; - int stream_count; - odp_shm_t shm; - odp_cpumask_t cpumask; - char cpumaskstr[ODP_CPUMASK_STR_SIZE]; - odp_pool_param_t params; - odp_instance_t instance; - odp_init_t init_param; - odph_odpthread_params_t thr_params; - - /* create by default scheduled queues */ - queue_create = odp_queue_create; - schedule_fn = odp_schedule_cb; - - /* check for using poll queues */ - if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) { - queue_create = polled_odp_queue_create; - schedule_fn = polled_odp_schedule_cb; - } - - /* Let helper collect its own arguments (e.g. --odph_proc) */ - argc = odph_parse_options(argc, argv); - if (odph_options(&helper_options)) { - ODPH_ERR("Error: reading ODP helper options failed.\n"); - exit(EXIT_FAILURE); - } - - /* Signal handler has to be registered before global init in case ODP - * implementation creates internal threads/processes. */ - signal(SIGINT, sig_handler); - - odp_init_param_init(&init_param); - init_param.mem_model = helper_options.mem_model; - - /* Init ODP before calling anything else */ - if (odp_init_global(&instance, &init_param, NULL)) { - ODPH_ERR("Error: ODP global init failed.\n"); - exit(EXIT_FAILURE); - } - - /* Init this thread */ - if (odp_init_local(instance, ODP_THREAD_CONTROL)) { - ODPH_ERR("Error: ODP local init failed.\n"); - exit(EXIT_FAILURE); - } - - /* Reserve memory for args from shared mem */ - shm = odp_shm_reserve("shm_args", sizeof(global_data_t), - ODP_CACHE_LINE_SIZE, 0); - - if (shm == ODP_SHM_INVALID) { - ODPH_ERR("Error: shared mem reserve failed.\n"); - exit(EXIT_FAILURE); - } - - global = odp_shm_addr(shm); - - if (NULL == global) { - ODPH_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(global, 0, sizeof(global_data_t)); - global->shm = shm; - odp_atomic_init_u32(&global->exit_threads, 0); - - /* Configure scheduler */ - odp_schedule_config(NULL); - - /* Must init our databases before parsing args */ - ipsec_init_pre(); - init_fwd_db(); - init_stream_db(); - - /* Parse and store the application arguments */ - parse_args(argc, argv, &global->appl); - - /* Print both system and application information */ - print_info(NO_PATH(argv[0]), &global->appl); - - num_workers = MAX_WORKERS; - if (global->appl.cpu_count && global->appl.cpu_count < MAX_WORKERS) - num_workers = global->appl.cpu_count; - - /* Get default worker cpumask */ - num_workers = odp_cpumask_default_worker(&cpumask, num_workers); - (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr)); - - printf("num worker threads: %i\n", num_workers); - printf("first CPU: %i\n", odp_cpumask_first(&cpumask)); - printf("cpu mask: %s\n", cpumaskstr); - - /* Create a barrier to synchronize thread startup */ - odp_barrier_init(&global->sync_barrier, num_workers); - - /* Create packet buffer pool */ - odp_pool_param_init(¶ms); - params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.num = SHM_PKT_POOL_BUF_COUNT; - params.type = ODP_POOL_PACKET; - - global->pkt_pool = odp_pool_create("packet_pool", ¶ms); - - if (ODP_POOL_INVALID == global->pkt_pool) { - ODPH_ERR("Error: packet pool create failed.\n"); - exit(EXIT_FAILURE); - } - - /* Create context buffer pool */ - params.buf.size = SHM_CTX_POOL_BUF_SIZE; - params.buf.align = 0; - params.buf.num = SHM_CTX_POOL_BUF_COUNT; - params.type = ODP_POOL_BUFFER; - - global->ctx_pool = odp_pool_create("ctx_pool", ¶ms); - - if (ODP_POOL_INVALID == global->ctx_pool) { - ODPH_ERR("Error: context pool create failed.\n"); - exit(EXIT_FAILURE); - } - - /* Populate our IPsec cache */ - printf("Using %s mode for crypto API\n\n", - (CRYPTO_API_SYNC == global->appl.mode) ? "SYNC" : - (CRYPTO_API_ASYNC_IN_PLACE == global->appl.mode) ? - "ASYNC_IN_PLACE" : "ASYNC_NEW_BUFFER"); - ipsec_init_post(global->appl.mode); - - /* Initialize interfaces (which resolves FWD DB entries */ - for (i = 0; i < global->appl.if_count; i++) - initialize_intf(global->appl.if_names[i]); - - /* If we have test streams build them before starting workers */ - resolve_stream_db(); - stream_count = create_stream_db_inputs(); - if (stream_count < 0) { - ODPH_ERR("Error: creating input packets failed\n"); - exit(EXIT_FAILURE); - } - - /* - * Create and init worker threads - */ - memset(thread_tbl, 0, sizeof(thread_tbl)); - memset(&thr_params, 0, sizeof(thr_params)); - thr_params.start = pktio_thread; - thr_params.arg = NULL; - thr_params.thr_type = ODP_THREAD_WORKER; - thr_params.instance = instance; - odph_odpthreads_create(thread_tbl, &cpumask, &thr_params); - - /* If there are streams attempt to verify them. Otherwise, run until - * SIGINT is received. */ - if (stream_count) { - odp_bool_t done; - - do { - done = verify_stream_db_outputs(); - sleep(1); - } while (!done); - printf("All received\n"); - odp_atomic_store_u32(&global->exit_threads, 1); - } - odph_odpthreads_join(thread_tbl); - - /* Stop and close used pktio devices */ - for (i = 0; i < global->appl.if_count; i++) { - odp_pktio_t pktio = odp_pktio_lookup(global->appl.if_names[i]); - - if (pktio == ODP_PKTIO_INVALID) - continue; - - if (odp_pktio_stop(pktio) || odp_pktio_close(pktio)) { - ODPH_ERR("Error: failed to close pktio %s\n", - global->appl.if_names[i]); - exit(EXIT_FAILURE); - } - } - - free(global->appl.if_names); - free(global->appl.if_str); - - if (destroy_ipsec_cache()) - ODPH_ERR("Error: crypto session destroy failed\n"); - - if (odp_queue_destroy(global->completionq)) - ODPH_ERR("Error: queue destroy failed\n"); - if (odp_queue_destroy(global->seqnumq)) - ODPH_ERR("Error: queue destroy failed\n"); - - if (odp_pool_destroy(global->pkt_pool)) - ODPH_ERR("Error: pool destroy failed\n"); - if (odp_pool_destroy(global->ctx_pool)) - ODPH_ERR("Error: pool destroy failed\n"); - if (odp_pool_destroy(global->out_pool)) - ODPH_ERR("Error: pool destroy failed\n"); - - shm = odp_shm_lookup("shm_ipsec_cache"); - if (odp_shm_free(shm) != 0) - ODPH_ERR("Error: shm free shm_ipsec_cache failed\n"); - shm = odp_shm_lookup("shm_fwd_db"); - if (odp_shm_free(shm) != 0) - ODPH_ERR("Error: shm free shm_fwd_db failed\n"); - shm = odp_shm_lookup("shm_sa_db"); - if (odp_shm_free(shm) != 0) - ODPH_ERR("Error: shm free shm_sa_db failed\n"); - shm = odp_shm_lookup("shm_tun_db"); - if (odp_shm_free(shm) != 0) - ODPH_ERR("Error: shm free shm_tun_db failed\n"); - shm = odp_shm_lookup("shm_sp_db"); - if (odp_shm_free(shm) != 0) - ODPH_ERR("Error: shm free shm_sp_db failed\n"); - shm = odp_shm_lookup("stream_db"); - if (odp_shm_free(shm) != 0) - ODPH_ERR("Error: shm free stream_db failed\n"); - if (odp_shm_free(global->shm)) { - ODPH_ERR("Error: shm free global data failed\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_local()) { - ODPH_ERR("Error: term local failed\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_global(instance)) { - ODPH_ERR("Error: term global failed\n"); - exit(EXIT_FAILURE); - } - - printf("Exit\n\n"); - - return 0; -} - -/** - * Parse and store the command line arguments - * - * @param argc argument count - * @param argv[] argument vector - * @param appl_args Store application arguments here - */ -static void parse_args(int argc, char *argv[], appl_args_t *appl_args) -{ - int opt; - int long_index; - char *token; - size_t len; - int rc = 0; - int i; - - static const struct option longopts[] = { - {"count", required_argument, NULL, 'c'}, - {"interface", required_argument, NULL, 'i'}, /* return 'i' */ - {"mode", required_argument, NULL, 'm'}, /* return 'm' */ - {"route", required_argument, NULL, 'r'}, /* return 'r' */ - {"policy", required_argument, NULL, 'p'}, /* return 'p' */ - {"ah", required_argument, NULL, 'a'}, /* return 'a' */ - {"esp", required_argument, NULL, 'e'}, /* return 'e' */ - {"tunnel", required_argument, NULL, 't'}, /* return 't' */ - {"stream", required_argument, NULL, 's'}, /* return 's' */ - {"help", no_argument, NULL, 'h'}, /* return 'h' */ - {NULL, 0, NULL, 0} - }; - - static const char *shortopts = "+c:i:m:r:p:a:e:t:s:h"; - - printf("\nParsing command line options\n"); - - appl_args->cpu_count = 1; /* use one worker by default */ - appl_args->mode = 0; /* turn off async crypto API by default */ - - while (!rc) { - opt = getopt_long(argc, argv, shortopts, longopts, &long_index); - - if (-1 == opt) - break; /* No more options */ - - switch (opt) { - case 'c': - appl_args->cpu_count = atoi(optarg); - break; - /* parse packet-io interface names */ - case 'i': - len = strlen(optarg); - if (0 == len) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - len += 1; /* add room for '\0' */ - - appl_args->if_str = malloc(len); - if (appl_args->if_str == NULL) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - /* count the number of tokens separated by ',' */ - strcpy(appl_args->if_str, optarg); - for (token = strtok(appl_args->if_str, ","), i = 0; - token != NULL; - token = strtok(NULL, ","), i++) - ; - - appl_args->if_count = i; - - if (0 == appl_args->if_count) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - /* allocate storage for the if names */ - appl_args->if_names = - calloc(appl_args->if_count, sizeof(char *)); - - /* store the if names (reset names string) */ - strcpy(appl_args->if_str, optarg); - for (token = strtok(appl_args->if_str, ","), i = 0; - token != NULL; token = strtok(NULL, ","), i++) { - appl_args->if_names[i] = token; - } - break; - - case 'm': - appl_args->mode = atoi(optarg); - break; - - case 'r': - rc = create_fwd_db_entry(optarg, appl_args->if_names, - appl_args->if_count); - break; - - case 'p': - rc = create_sp_db_entry(optarg, TRUE); - break; - - case 'a': - rc = create_sa_db_entry(optarg, FALSE); - break; - - case 'e': - rc = create_sa_db_entry(optarg, TRUE); - break; - - case 't': - rc = create_tun_db_entry(optarg); - break; - - case 's': - rc = create_stream_db_entry(optarg); - break; - - case 'h': - usage(argv[0]); - exit(EXIT_SUCCESS); - break; - - default: - break; - } - } - - if (rc) { - printf("ERROR: failed parsing -%c option\n", opt); - usage(argv[0]); - exit(EXIT_FAILURE); - } - - if (0 == appl_args->if_count) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - optind = 1; /* reset 'extern optind' from the getopt lib */ -} - -/** - * Print system and application info - */ -static void print_info(char *progname, appl_args_t *appl_args) -{ - int i; - - odp_sys_info_print(); - - printf("Running ODP appl: \"%s\"\n" - "-----------------\n" - "IF-count: %i\n" - "Using IFs: ", - progname, appl_args->if_count); - for (i = 0; i < appl_args->if_count; ++i) - printf(" %s", appl_args->if_names[i]); - - printf("\n"); - - dump_fwd_db(); - dump_sp_db(); - dump_sa_db(); - dump_tun_db(); - printf("\n\n"); - fflush(NULL); -} - -/** - * Prinf usage information - */ -static void usage(char *progname) -{ - printf("\n" - "Usage: %s OPTIONS\n" - " E.g. %s -i eth1,eth2,eth3 -m 0\n" - "\n" - "OpenDataPlane example application.\n" - "\n" - "Mandatory OPTIONS:\n" - " -i, --interface Eth interfaces (comma-separated, no spaces)\n" - " -m, --mode 0: SYNC\n" - " 1: ASYNC_IN_PLACE\n" - " 2: ASYNC_NEW_BUFFER\n" - " Default: 0: SYNC api mode\n" - "\n" - "Routing / IPSec OPTIONS:\n" - " -r, --route SubNet:Intf:NextHopMAC\n" - " -p, --policy SrcSubNet:DstSubNet:(in|out):(ah|esp|both)\n" - " -e, --esp SrcIP:DstIP:(3des|null):SPI:Key192\n" - " -a, --ah SrcIP:DstIP:(sha256|md5|null):SPI:Key(256|128)\n" - "\n" - " Where: NextHopMAC is raw hex/dot notation, i.e. 03.BA.44.9A.CE.02\n" - " IP is decimal/dot notation, i.e. 192.168.1.1\n" - " SubNet is decimal/dot/slash notation, i.e 192.168.0.0/16\n" - " SPI is raw hex, 32 bits\n" - " KeyXXX is raw hex, XXX bits long\n" - "\n" - " Examples:\n" - " -r 192.168.222.0/24:p8p1:08.00.27.F5.8B.DB\n" - " -p 192.168.111.0/24:192.168.222.0/24:out:esp\n" - " -e 192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n" - " -a 192.168.111.2:192.168.222.2:md5:201:a731649644c5dee92cbd9c2e7e188ee6\n" - "\n" - "Optional OPTIONS\n" - " -c, --count CPU count, 0=all available, default=1\n" - " -s, --stream SrcIP:DstIP:InIntf:OutIntf:Count:Length\n" - " -h, --help Display help and exit.\n" - " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n" - " to enable use of poll queues instead of scheduled (default)\n" - " ODP_IPSEC_STREAM_VERIFY_MDEQ\n" - " to enable use of multiple dequeue for queue draining during\n" - " stream verification instead of single dequeue (default)\n" - "\n", NO_PATH(progname), NO_PATH(progname) - ); -} diff --git a/example/ipsec/odp_ipsec_cache.c b/example/ipsec/odp_ipsec_cache.c deleted file mode 100644 index 044538c59..000000000 --- a/example/ipsec/odp_ipsec_cache.c +++ /dev/null @@ -1,243 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include - -#include - -#include - -#include - -/** Global pointer to ipsec_cache db */ -ipsec_cache_t *ipsec_cache; - -void init_ipsec_cache(void) -{ - odp_shm_t shm; - int i; - - shm = odp_shm_reserve("shm_ipsec_cache", - sizeof(ipsec_cache_t), - ODP_CACHE_LINE_SIZE, - 0); - if (shm == ODP_SHM_INVALID) { - ODPH_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - - ipsec_cache = odp_shm_addr(shm); - - if (ipsec_cache == NULL) { - ODPH_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(ipsec_cache, 0, sizeof(*ipsec_cache)); - - for (i = 0; i < MAX_DB; i++) - ipsec_cache->array[i].state.session = - ODP_CRYPTO_SESSION_INVALID; -} - -int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa, - sa_db_entry_t *auth_sa, - tun_db_entry_t *tun, - crypto_api_mode_e api_mode, - odp_bool_t in, - odp_queue_t completionq, - odp_pool_t out_pool) -{ - odp_crypto_session_param_t params; - ipsec_cache_entry_t *entry; - odp_crypto_ses_create_err_t ses_create_rc; - odp_crypto_session_t session; - sa_mode_t mode = IPSEC_SA_MODE_TRANSPORT; - - /* Verify we have a good entry */ - entry = &ipsec_cache->array[ipsec_cache->index]; - if (MAX_DB <= ipsec_cache->index) - return -1; - - /* Verify SA mode match in case of cipher&auth */ - if (cipher_sa && auth_sa && - (cipher_sa->mode != auth_sa->mode)) - return -1; - - odp_crypto_session_param_init(¶ms); - - /* Setup parameters and call crypto library to create session */ - params.op = (in) ? ODP_CRYPTO_OP_DECODE : ODP_CRYPTO_OP_ENCODE; - params.auth_cipher_text = TRUE; - if (CRYPTO_API_SYNC == api_mode) { - params.op_mode = ODP_CRYPTO_SYNC; - params.compl_queue = ODP_QUEUE_INVALID; - params.output_pool = ODP_POOL_INVALID; - entry->async = FALSE; - } else { - params.op_mode = ODP_CRYPTO_ASYNC; - params.compl_queue = completionq; - params.output_pool = out_pool; - entry->async = TRUE; - } - - if (CRYPTO_API_ASYNC_NEW_BUFFER == api_mode) - entry->in_place = FALSE; - else - entry->in_place = TRUE; - - - /* Cipher */ - if (cipher_sa) { - params.cipher_alg = cipher_sa->alg.u.cipher; - params.cipher_key.data = cipher_sa->key.data; - params.cipher_key.length = cipher_sa->key.length; - params.cipher_iv.data = entry->state.iv; - params.cipher_iv.length = cipher_sa->iv_len; - mode = cipher_sa->mode; - } else { - params.cipher_alg = ODP_CIPHER_ALG_NULL; - params.cipher_iv.data = NULL; - params.cipher_iv.length = 0; - } - - /* Auth */ - if (auth_sa) { - params.auth_alg = auth_sa->alg.u.auth; - params.auth_key.data = auth_sa->key.data; - params.auth_key.length = auth_sa->key.length; - params.auth_digest_len = auth_sa->icv_len; - mode = auth_sa->mode; - } else { - params.auth_alg = ODP_AUTH_ALG_NULL; - } - - /* Generate an IV */ - if (params.cipher_iv.length) { - int32_t size = params.cipher_iv.length; - - int32_t ret = odp_random_data(params.cipher_iv.data, size, 1); - if (ret != size) - return -1; - } - - /* Synchronous session create for now */ - if (odp_crypto_session_create(¶ms, &session, &ses_create_rc)) - return -1; - if (ODP_CRYPTO_SES_CREATE_ERR_NONE != ses_create_rc) - return -1; - - /* Copy remainder */ - if (cipher_sa) { - entry->src_ip = cipher_sa->src_ip; - entry->dst_ip = cipher_sa->dst_ip; - entry->esp.alg = cipher_sa->alg.u.cipher; - entry->esp.spi = cipher_sa->spi; - entry->esp.block_len = cipher_sa->block_len; - entry->esp.iv_len = cipher_sa->iv_len; - memcpy(&entry->esp.key, &cipher_sa->key, sizeof(ipsec_key_t)); - } - if (auth_sa) { - entry->src_ip = auth_sa->src_ip; - entry->dst_ip = auth_sa->dst_ip; - entry->ah.alg = auth_sa->alg.u.auth; - entry->ah.spi = auth_sa->spi; - entry->ah.icv_len = auth_sa->icv_len; - memcpy(&entry->ah.key, &auth_sa->key, sizeof(ipsec_key_t)); - } - - if (tun) { - entry->tun_src_ip = tun->tun_src_ip; - entry->tun_dst_ip = tun->tun_dst_ip; - mode = IPSEC_SA_MODE_TUNNEL; - - int ret; - - if (!in) { - /* init tun hdr id */ - ret = odp_random_data((uint8_t *) - &entry->state.tun_hdr_id, - sizeof(entry->state.tun_hdr_id), - 1); - if (ret != sizeof(entry->state.tun_hdr_id)) - return -1; - } - } - entry->mode = mode; - - /* Initialize state */ - entry->state.esp_seq = 0; - entry->state.ah_seq = 0; - entry->state.session = session; - - /* Add entry to the appropriate list */ - ipsec_cache->index++; - if (in) { - entry->next = ipsec_cache->in_list; - ipsec_cache->in_list = entry; - } else { - entry->next = ipsec_cache->out_list; - ipsec_cache->out_list = entry; - } - - return 0; -} - -ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip, - uint32_t dst_ip, - odph_ahhdr_t *ah, - odph_esphdr_t *esp) -{ - ipsec_cache_entry_t *entry = ipsec_cache->in_list; - - /* Look for a hit */ - for (; NULL != entry; entry = entry->next) { - if ((entry->src_ip != src_ip) || (entry->dst_ip != dst_ip)) - if ((entry->tun_src_ip != src_ip) || - (entry->tun_dst_ip != dst_ip)) - continue; - if (ah && - ((!entry->ah.alg) || - (entry->ah.spi != odp_be_to_cpu_32(ah->spi)))) - continue; - if (esp && - ((!entry->esp.alg) || - (entry->esp.spi != odp_be_to_cpu_32(esp->spi)))) - continue; - break; - } - - return entry; -} - -ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip, - uint32_t dst_ip, - uint8_t proto ODP_UNUSED) -{ - ipsec_cache_entry_t *entry = ipsec_cache->out_list; - - /* Look for a hit */ - for (; NULL != entry; entry = entry->next) { - if ((entry->src_ip == src_ip) && (entry->dst_ip == dst_ip)) - break; - } - return entry; -} - -int destroy_ipsec_cache(void) -{ - ipsec_cache_entry_t *entry; - int i; - int ret = 0; - - for (i = 0; i < MAX_DB; i++) { - entry = &ipsec_cache->array[i]; - if (entry->state.session != ODP_CRYPTO_SESSION_INVALID) - ret += odp_crypto_session_destroy(entry->state.session); - } - - return ret; -} diff --git a/example/ipsec/odp_ipsec_cache.h b/example/ipsec/odp_ipsec_cache.h deleted file mode 100644 index 1523778ff..000000000 --- a/example/ipsec/odp_ipsec_cache.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_CACHE_H_ -#define ODP_IPSEC_CACHE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#include -#include - -/** - * Mode specified on command line indicating how to exercise API - */ -typedef enum { - CRYPTO_API_SYNC, /**< Synchronous mode */ - CRYPTO_API_ASYNC_IN_PLACE, /**< Asynchronous in place */ - CRYPTO_API_ASYNC_NEW_BUFFER /**< Asynchronous new buffer */ -} crypto_api_mode_e; - -/** - * IPsec cache data base entry - */ -typedef struct ipsec_cache_entry_s { - struct ipsec_cache_entry_s *next; /**< Next entry on list */ - odp_bool_t in_place; /**< Crypto API mode */ - odp_bool_t async; /**< ASYNC or SYNC mode */ - uint32_t src_ip; /**< Source v4 address */ - uint32_t dst_ip; /**< Destination v4 address */ - sa_mode_t mode; /**< SA mode - transport/tun */ - uint32_t tun_src_ip; /**< Tunnel src IPv4 addr */ - uint32_t tun_dst_ip; /**< Tunnel dst IPv4 addr */ - struct { - odp_cipher_alg_t alg; /**< Cipher algorithm */ - uint32_t spi; /**< Cipher SPI */ - uint32_t block_len; /**< Cipher block length */ - uint32_t iv_len; /**< Cipher IV length */ - ipsec_key_t key; /**< Cipher key */ - } esp; - struct { - odp_auth_alg_t alg; /**< Auth algorithm */ - uint32_t spi; /**< Auth SPI */ - uint32_t icv_len; /**< Auth ICV length */ - ipsec_key_t key; /**< Auth key */ - } ah; - - /* Per SA state */ - struct { - odp_crypto_session_t session; /**< Crypto session handle */ - uint32_t esp_seq; /**< ESP TX sequence number */ - uint32_t ah_seq; /**< AH TX sequence number */ - uint8_t iv[MAX_IV_LEN]; /**< ESP IV storage */ - odp_u16be_t tun_hdr_id; /**< Tunnel header IP ID */ - } state; -} ipsec_cache_entry_t; - -/** - * IPsec cache data base global structure - */ -typedef struct ipsec_cache_s { - uint32_t index; /**< Index of next available entry */ - ipsec_cache_entry_t *in_list; /**< List of active input entries */ - ipsec_cache_entry_t *out_list; /**< List of active output entries */ - ipsec_cache_entry_t array[MAX_DB]; /**< Entry storage */ -} ipsec_cache_t; - -/** Global pointer to ipsec_cache db */ -extern ipsec_cache_t *ipsec_cache; - -/** Initialize IPsec cache */ -void init_ipsec_cache(void); - -/** - * Create an entry in the IPsec cache - * - * @param cipher_sa Cipher SA DB entry pointer - * @param auth_sa Auth SA DB entry pointer - * @param tun Tunnel DB entry pointer - * @param api_mode Crypto API mode for testing - * @param in Direction (input versus output) - * @param completionq Completion queue - * @param out_pool Output buffer pool - * - * @return 0 if successful else -1 - */ -int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa, - sa_db_entry_t *auth_sa, - tun_db_entry_t *tun, - crypto_api_mode_e api_mode, - odp_bool_t in, - odp_queue_t completionq, - odp_pool_t out_pool); - -/** - * Find a matching IPsec cache entry for input packet - * - * @param src_ip Source IPv4 address - * @param dst_ip Destination IPv4 address - * @param ah Pointer to AH header in packet else NULL - * @param esp Pointer to ESP header in packet else NULL - * - * @return pointer to IPsec cache entry else NULL - */ -ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip, - uint32_t dst_ip, - odph_ahhdr_t *ah, - odph_esphdr_t *esp); - -/** - * Find a matching IPsec cache entry for output packet - * - * @param src_ip Source IPv4 address - * @param dst_ip Destination IPv4 address - * @param proto IPv4 protocol (currently all protocols match) - * - * @return pointer to IPsec cache entry else NULL - */ -ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip, - uint32_t dst_ip, - uint8_t proto); - -int destroy_ipsec_cache(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/example/ipsec/odp_ipsec_fwd_db.c b/example/ipsec/odp_ipsec_fwd_db.c deleted file mode 100644 index ca0abf6c1..000000000 --- a/example/ipsec/odp_ipsec_fwd_db.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* enable strtok */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include - -#include -#include - -#include - -/** Global pointer to fwd db */ -fwd_db_t *fwd_db; - -void init_fwd_db(void) -{ - odp_shm_t shm; - - shm = odp_shm_reserve("shm_fwd_db", - sizeof(fwd_db_t), - ODP_CACHE_LINE_SIZE, - 0); - - if (shm == ODP_SHM_INVALID) { - ODPH_ERR("Error: shared mem reserve failed.\n"); - exit(EXIT_FAILURE); - } - - fwd_db = odp_shm_addr(shm); - - if (fwd_db == NULL) { - ODPH_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(fwd_db, 0, sizeof(*fwd_db)); -} - -int create_fwd_db_entry(char *input, char **if_names, int if_count) -{ - int pos = 0, i, match = 0; - char *local; - char *str; - char *save; - char *token; - fwd_db_entry_t *entry = &fwd_db->array[fwd_db->index]; - - /* Verify we haven't run out of space */ - if (MAX_DB <= fwd_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->subnet.addr, - &entry->subnet.mask); - break; - case 1: - strncpy(entry->oif, token, OIF_LEN - 1); - entry->oif[OIF_LEN - 1] = 0; - for (i = 0; i < if_count; i++) { - if (!strcmp(if_names[i], entry->oif)) { - match = 1; - break; - } - } - if (!match) { - printf("ERROR: interface name not correct for route\n"); - free(local); - return -1; - } - break; - case 2: - parse_mac_string(token, entry->dst_mac); - 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 (3 != pos) { - printf("ERROR: \"%s\" contains %d tokens, expected 3\n", - input, - pos); - free(local); - return -1; - } - - /* Add route to the list */ - fwd_db->index++; - entry->next = fwd_db->list; - fwd_db->list = entry; - - free(local); - return 0; -} - -void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout, - uint8_t *mac) -{ - fwd_db_entry_t *entry; - - /* Walk the list and attempt to set output queue and MAC */ - for (entry = fwd_db->list; NULL != entry; entry = entry->next) { - if (strcmp(intf, entry->oif)) - continue; - - entry->pktio = pktio; - entry->pktout = pktout; - memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN); - } -} - -void dump_fwd_db_entry(fwd_db_entry_t *entry) -{ - char subnet_str[MAX_STRING]; - char mac_str[MAX_STRING]; - - printf(" %s %s %s\n", - ipv4_subnet_str(subnet_str, &entry->subnet), - entry->oif, - mac_addr_str(mac_str, entry->dst_mac)); -} - -void dump_fwd_db(void) -{ - fwd_db_entry_t *entry; - - printf("\n" - "Routing table\n" - "-------------\n"); - - for (entry = fwd_db->list; NULL != entry; entry = entry->next) - dump_fwd_db_entry(entry); -} - -fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip) -{ - fwd_db_entry_t *entry; - - for (entry = fwd_db->list; NULL != entry; entry = entry->next) - if (entry->subnet.addr == (dst_ip & entry->subnet.mask)) - break; - return entry; -} diff --git a/example/ipsec/odp_ipsec_fwd_db.h b/example/ipsec/odp_ipsec_fwd_db.h deleted file mode 100644 index 278259729..000000000 --- a/example/ipsec/odp_ipsec_fwd_db.h +++ /dev/null @@ -1,98 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_FWD_DB_H_ -#define ODP_IPSEC_FWD_DB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#define OIF_LEN 32 - -/** - * Forwarding data base entry - */ -typedef struct fwd_db_entry_s { - struct fwd_db_entry_s *next; /**< Next entry on list */ - char oif[OIF_LEN]; /**< Output interface name */ - odp_pktio_t pktio; /**< Output PktI/O interface */ - odp_pktout_queue_t pktout; /**< Output transmit queue */ - uint8_t src_mac[ODPH_ETHADDR_LEN]; /**< Output source MAC */ - uint8_t dst_mac[ODPH_ETHADDR_LEN]; /**< Output destination MAC */ - ip_addr_range_t subnet; /**< Subnet for this router */ -} fwd_db_entry_t; - -/** - * Forwarding data base global structure - */ -typedef struct fwd_db_s { - uint32_t index; /**< Next available entry */ - fwd_db_entry_t *list; /**< List of active routes */ - fwd_db_entry_t array[MAX_DB]; /**< Entry storage */ -} fwd_db_t; - -/** Global pointer to fwd db */ -extern fwd_db_t *fwd_db; - -/** Initialize FWD DB */ -void init_fwd_db(void); - -/** - * Create a forwarding database entry - * - * String is of the format "SubNet:Intf:NextHopMAC" - * - * @param input Pointer to string describing route - * - * @param if_names Array of Name of the interfaces available - * - * @param if_count number of interfaces in if_names array - * - * @return 0 if successful else -1 - */ -int create_fwd_db_entry(char *input, char **if_names, int if_count); - -/** - * Scan FWD DB entries and resolve output queue and source MAC address - * - * @param intf Interface name string - * @param pktio Output packet interface - * @param outq Output queue for packet transmit - * @param mac MAC address of this interface - */ -void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout, - uint8_t *mac); - -/** - * Display one fowarding database entry - * - * @param entry Pointer to entry to display - */ -void dump_fwd_db_entry(fwd_db_entry_t *entry); - -/** - * Display the forwarding database - */ -void dump_fwd_db(void); - -/** - * Find a matching forwarding database entry - * - * @param dst_ip Destination IPv4 address - * - * @return pointer to forwarding DB entry else NULL - */ -fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/example/ipsec/odp_ipsec_misc.h b/example/ipsec/odp_ipsec_misc.h deleted file mode 100644 index 71d8f63c4..000000000 --- a/example/ipsec/odp_ipsec_misc.h +++ /dev/null @@ -1,343 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_MISC_H_ -#define ODP_IPSEC_MISC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define MAX_DB 32 /**< maximum number of data base entries */ -#define MAX_LOOPBACK 10 /**< maximum number of loop back interfaces */ -#define MAX_STRING 32 /**< maximum string length */ -#define MAX_IV_LEN 32 /**< Maximum IV length in bytes */ - -#define KEY_BITS_3DES 192 /**< 3DES cipher key length in bits */ -#define KEY_BITS_MD5_96 128 /**< MD5_96 auth key length in bits */ -#define KEY_BITS_SHA256_128 256 /**< SHA256_128 auth key length in bits */ - -/**< Number of bits represnted by a string of hexadecimal characters */ -#define KEY_STR_BITS(str) (4 * strlen(str)) - -/** IPv4 helpers for data length and uint8t pointer */ -#define ipv4_data_len(ip) (odp_be_to_cpu_16(ip->tot_len) - sizeof(odph_ipv4hdr_t)) -#define ipv4_data_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1)) - -/** Helper for calculating encode length using data length and block size */ -#define ESP_ENCODE_LEN(x, b) ((((x) + (b - 1)) / b) * b) - -/** Get rid of path in filename - only for unix-type paths using '/' */ -#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ - strrchr((file_name), '/') + 1 : (file_name)) - -/** - * IPsec key - */ -typedef struct { - uint8_t data[32]; /**< Key data */ - uint8_t length; /**< Key length */ -} ipsec_key_t; - -/** - * IPsec algorithm - */ -typedef struct { - odp_bool_t cipher; - union { - odp_cipher_alg_t cipher; - odp_auth_alg_t auth; - } u; -} ipsec_alg_t; - -/** - * IP address range (subnet) - */ -typedef struct ip_addr_range_s { - uint32_t addr; /**< IP address */ - uint32_t mask; /**< mask, 1 indicates bits are valid */ -} ip_addr_range_t; - -/** - * Parse text string representing a key into ODP key structure - * - * @param keystring Pointer to key string to convert - * @param key Pointer to ODP key structure to populate - * @param alg Cipher/authentication algorithm associated with the key - * - * @return 0 if successful else -1 - */ -static inline -int parse_key_string(char *keystring, - ipsec_key_t *key, - ipsec_alg_t *alg) -{ - int idx; - int key_bits_in = KEY_STR_BITS(keystring); - char temp[3]; - - key->length = 0; - - /* Algorithm is either cipher or authentication */ - if (alg->cipher) { - if ((alg->u.cipher == ODP_CIPHER_ALG_3DES_CBC) && - (KEY_BITS_3DES == key_bits_in)) - key->length = key_bits_in / 8; - - } else { - if ((alg->u.auth == ODP_AUTH_ALG_MD5_HMAC) && - (KEY_BITS_MD5_96 == key_bits_in)) - key->length = key_bits_in / 8; - else if ((alg->u.auth == ODP_AUTH_ALG_SHA256_HMAC) && - (KEY_BITS_SHA256_128 == key_bits_in)) - key->length = key_bits_in / 8; - } - - for (idx = 0; idx < key->length; idx++) { - temp[0] = *keystring++; - temp[1] = *keystring++; - temp[2] = 0; - key->data[idx] = strtol(temp, NULL, 16); - } - - return key->length ? 0 : -1; -} - -/** - * Check IPv4 address against a range/subnet - * - * @param addr IPv4 address to check - * @param range Pointer to address range to check against - * - * @return 1 if match else 0 - */ -static inline -int match_ip_range(uint32_t addr, ip_addr_range_t *range) -{ - return (range->addr == (addr & range->mask)); -} - -/** - * Generate text string representing IPv4 address - * - * @param b Pointer to buffer to store string - * @param addr IPv4 address - * - * @return Pointer to supplied buffer - */ -static inline -char *ipv4_addr_str(char *b, uint32_t addr) -{ - sprintf(b, "%03d.%03d.%03d.%03d", - 0xFF & ((addr) >> 24), - 0xFF & ((addr) >> 16), - 0xFF & ((addr) >> 8), - 0xFF & ((addr) >> 0)); - return b; -} - -/** - * Parse text string representing an IPv4 address or subnet - * - * String is of the format "XXX.XXX.XXX.XXX(/W)" where - * "XXX" is decimal value and "/W" is optional subnet length - * - * @param ipaddress Pointer to IP address/subnet string to convert - * @param addr Pointer to return IPv4 address - * @param mask Pointer (optional) to return IPv4 mask - * - * @return 0 if successful else -1 - */ -static inline -int parse_ipv4_string(char *ipaddress, uint32_t *addr, uint32_t *mask) -{ - int b[4]; - int qualifier = 32; - int converted; - - if (strchr(ipaddress, '/')) { - converted = sscanf(ipaddress, "%d.%d.%d.%d/%d", - &b[3], &b[2], &b[1], &b[0], - &qualifier); - if (5 != converted) - return -1; - } else { - converted = sscanf(ipaddress, "%d.%d.%d.%d", - &b[3], &b[2], &b[1], &b[0]); - if (4 != converted) - return -1; - } - - if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255)) - return -1; - if (!qualifier || (qualifier > 32)) - return -1; - - *addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; - if (mask) - *mask = ~(0xFFFFFFFF & ((1ULL << (32 - qualifier)) - 1)); - - return 0; -} - -/** - * Generate text string representing IPv4 range/subnet, output - * in "XXX.XXX.XXX.XXX/W" format - * - * @param b Pointer to buffer to store string - * @param range Pointer to IPv4 address range - * - * @return Pointer to supplied buffer - */ -static inline -char *ipv4_subnet_str(char *b, ip_addr_range_t *range) -{ - int idx; - int len; - - for (idx = 0; idx < 32; idx++) - if (range->mask & (1 << idx)) - break; - len = 32 - idx; - - sprintf(b, "%03d.%03d.%03d.%03d/%d", - 0xFF & ((range->addr) >> 24), - 0xFF & ((range->addr) >> 16), - 0xFF & ((range->addr) >> 8), - 0xFF & ((range->addr) >> 0), - len); - return b; -} - -/** - * Generate text string representing MAC address - * - * @param b Pointer to buffer to store string - * @param mac Pointer to MAC address - * - * @return Pointer to supplied buffer - */ -static inline -char *mac_addr_str(char *b, uint8_t *mac) -{ - sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - return b; -} - -/** - * Parse text string representing a MAC address into byte araray - * - * String is of the format "XX.XX.XX.XX.XX.XX" where XX is hexadecimal - * - * @param macaddress Pointer to MAC address string to convert - * @param mac Pointer to MAC address byte array to populate - * - * @return 0 if successful else -1 - */ -static inline -int parse_mac_string(char *macaddress, uint8_t *mac) -{ - int macwords[ODPH_ETHADDR_LEN]; - int converted; - - converted = sscanf(macaddress, - "%x.%x.%x.%x.%x.%x", - &macwords[0], &macwords[1], &macwords[2], - &macwords[3], &macwords[4], &macwords[5]); - if (6 != converted) - return -1; - - mac[0] = macwords[0]; - mac[1] = macwords[1]; - mac[2] = macwords[2]; - mac[3] = macwords[3]; - mac[4] = macwords[4]; - mac[5] = macwords[5]; - - return 0; -} - -/** - * Locate IPsec headers (AH and/or ESP) in packet - * - * @param ip Pointer to packets IPv4 header - * @param ah_p Pointer to location to return AH header pointer - * @param esp_p Pointer to location to return ESP header pointer - * - * @return length of IPsec headers found - */ -static inline -int locate_ipsec_headers(odph_ipv4hdr_t *ip, - odph_ahhdr_t **ah_p, - odph_esphdr_t **esp_p) -{ - uint8_t *in = ipv4_data_p(ip); - odph_ahhdr_t *ah = NULL; - odph_esphdr_t *esp = NULL; - - if (ODPH_IPPROTO_AH == ip->proto) { - ah = (odph_ahhdr_t *)in; - in += ((ah)->ah_len + 2) * 4; - if (ODPH_IPPROTO_ESP == ah->next_header) { - esp = (odph_esphdr_t *)in; - in += sizeof(odph_esphdr_t); - } - } else if (ODPH_IPPROTO_ESP == ip->proto) { - esp = (odph_esphdr_t *)in; - in += sizeof(odph_esphdr_t); - } - - *ah_p = ah; - *esp_p = esp; - return in - (ipv4_data_p(ip)); -} - -/** - * Adjust IPv4 length - * - * @param ip Pointer to IPv4 header - * @param adj Signed adjustment value - */ -static inline -void ipv4_adjust_len(odph_ipv4hdr_t *ip, int adj) -{ - ip->tot_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->tot_len) + adj); -} - -/** - * Verify crypto operation completed successfully - * - * @param status Pointer to cryto completion structure - * - * @return TRUE if all OK else FALSE - */ -static inline -odp_bool_t is_crypto_op_status_ok(odp_crypto_op_status_t *status) -{ - if (status->alg_err != ODP_CRYPTO_ALG_ERR_NONE) - return FALSE; - if (status->hw_err != ODP_CRYPTO_HW_ERR_NONE) - return FALSE; - return TRUE; -} - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/example/ipsec/odp_ipsec_run_ah_in.sh b/example/ipsec/odp_ipsec_run_ah_in.sh deleted file mode 100755 index 5ff168760..000000000 --- a/example/ipsec/odp_ipsec_run_ah_in.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# -# Test input AH -# - 2 loop interfaces -# - 10 packets -# - Specify API mode on command line -./odp_ipsec -i loop1,loop2 \ --r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ --p 192.168.222.0/24:192.168.111.0/24:in:ah \ --a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ --s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ --c 2 -m $1 diff --git a/example/ipsec/odp_ipsec_run_ah_out.sh b/example/ipsec/odp_ipsec_run_ah_out.sh deleted file mode 100755 index 53ddd2fb1..000000000 --- a/example/ipsec/odp_ipsec_run_ah_out.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# -# Test output AH -# - 2 loop interfaces -# - 10 packets -# - Specify API mode on command line -./odp_ipsec -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:ah \ --a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ --c 2 -m $1 diff --git a/example/ipsec/odp_ipsec_run_both_in.sh b/example/ipsec/odp_ipsec_run_both_in.sh deleted file mode 100755 index 502f14a7d..000000000 --- a/example/ipsec/odp_ipsec_run_both_in.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# -# Test AH and ESP input -# - 2 loop interfaces -# - 10 packets -# - Specify API mode on command line -./odp_ipsec -i loop1,loop2 \ --r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ --p 192.168.222.0/24:192.168.111.0/24:in:both \ --a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ --e 192.168.222.2:192.168.111.2:\ -3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ --s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ --c 2 -m $1 diff --git a/example/ipsec/odp_ipsec_run_both_out.sh b/example/ipsec/odp_ipsec_run_both_out.sh deleted file mode 100755 index 3086e6f12..000000000 --- a/example/ipsec/odp_ipsec_run_both_out.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# -# Test AH and ESP output -# - 2 loop interfaces -# - 10 packets -# - Specify API mode on command line -./odp_ipsec -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:both \ --e 192.168.111.2:192.168.222.2:\ -3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ --c 2 -m $1 diff --git a/example/ipsec/odp_ipsec_run_esp_in.sh b/example/ipsec/odp_ipsec_run_esp_in.sh deleted file mode 100755 index a206cc401..000000000 --- a/example/ipsec/odp_ipsec_run_esp_in.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -# -# Test input ESP -# - 2 loop interfaces -# - 10 packets -# - Specify API mode on command line -./odp_ipsec -i loop1,loop2 \ --r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ --p 192.168.222.0/24:192.168.111.0/24:in:esp \ --e 192.168.222.2:192.168.111.2:\ -3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ --s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ --c 2 -m $1 diff --git a/example/ipsec/odp_ipsec_run_esp_out.sh b/example/ipsec/odp_ipsec_run_esp_out.sh deleted file mode 100755 index f8645f0fb..000000000 --- a/example/ipsec/odp_ipsec_run_esp_out.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Test output ESP -# - 2 loop interfaces -# - 10 packets -# - Specify API mode on command line - -if [ -z "$IPSEC_EXAMPLE_PATH" ]; then -IPSEC_EXAMPLE_PATH=. -fi - -${IPSEC_EXAMPLE_PATH}/odp_ipsec -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:esp \ --e 192.168.111.2:192.168.222.2:\ -3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ --c 2 "$@" diff --git a/example/ipsec/odp_ipsec_run_live.sh b/example/ipsec/odp_ipsec_run_live.sh deleted file mode 100755 index f61d4e38f..000000000 --- a/example/ipsec/odp_ipsec_run_live.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Live router test -# - 2 interfaces interfaces -# - Specify API mode on command line -sudo ./odp_ipsec -i p7p1,p8p1 \ --r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ --r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:both \ --e 192.168.111.2:192.168.222.2:\ -3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ --p 192.168.222.0/24:192.168.111.0/24:in:both \ --e 192.168.222.2:192.168.111.2:\ -3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ --a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ --c 2 -m $1 diff --git a/example/ipsec/odp_ipsec_run_router.sh b/example/ipsec/odp_ipsec_run_router.sh deleted file mode 100755 index 55ad766f5..000000000 --- a/example/ipsec/odp_ipsec_run_router.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# -# Live router test -# - 2 interfaces interfaces -# - Specify API mode on command line -sudo ./odp_ipsec -i p7p1,p8p1 \ --r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ --r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ --c 1 -m $1 diff --git a/example/ipsec/odp_ipsec_run_simple.sh b/example/ipsec/odp_ipsec_run_simple.sh deleted file mode 100755 index 3c3710f5f..000000000 --- a/example/ipsec/odp_ipsec_run_simple.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# -# Simple router test -# - 2 loop interfaces -# - 10 packets -# - Specify API mode on command line - -if [ -z "$IPSEC_EXAMPLE_PATH" ]; then -IPSEC_EXAMPLE_PATH=. -fi - -${IPSEC_EXAMPLE_PATH}/odp_ipsec -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ --c 2 "$@" diff --git a/example/ipsec/odp_ipsec_sa_db.c b/example/ipsec/odp_ipsec_sa_db.c deleted file mode 100644 index 9a7c593b3..000000000 --- a/example/ipsec/odp_ipsec_sa_db.c +++ /dev/null @@ -1,328 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* enable strtok */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include - -#include -#include - -#include - -/** Global pointer to sa db */ -static sa_db_t *sa_db; - -/** Global pointer to tun db */ -static tun_db_t *tun_db; - -void init_sa_db(void) -{ - odp_shm_t shm; - - shm = odp_shm_reserve("shm_sa_db", - sizeof(sa_db_t), - ODP_CACHE_LINE_SIZE, - 0); - - if (shm == ODP_SHM_INVALID) { - ODPH_ERR("Error: shared mem reserve failed.\n"); - exit(EXIT_FAILURE); - } - - sa_db = odp_shm_addr(shm); - - if (sa_db == NULL) { - ODPH_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(sa_db, 0, sizeof(*sa_db)); -} - -void init_tun_db(void) -{ - odp_shm_t shm; - - shm = odp_shm_reserve("shm_tun_db", - sizeof(tun_db_t), - ODP_CACHE_LINE_SIZE, - 0); - - if (shm == ODP_SHM_INVALID) { - ODPH_ERR("Error: shared mem reserve failed.\n"); - exit(EXIT_FAILURE); - } - - tun_db = odp_shm_addr(shm); - - if (!tun_db) { - ODPH_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(tun_db, 0, sizeof(*tun_db)); -} - -int create_sa_db_entry(char *input, odp_bool_t cipher) -{ - int pos = 0; - char *local; - char *str; - char *save; - char *token; - sa_db_entry_t *entry = &sa_db->array[sa_db->index]; - - /* Verify we have a good entry */ - if (MAX_DB <= sa_db->index) - return -1; - - /* Make a local copy */ - local = malloc(strlen(input) + 1); - if (NULL == local) - return -1; - strcpy(local, input); - - /* Set cipher versus auth */ - entry->alg.cipher = cipher; - - /* 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: - if (cipher) { - if (0 == strcmp(token, "3des")) { - entry->alg.u.cipher = - ODP_CIPHER_ALG_3DES_CBC; - entry->block_len = 8; - entry->iv_len = 8; - } else { - entry->alg.u.cipher = - ODP_CIPHER_ALG_NULL; - } - } else { - if (0 == strcmp(token, "md5")) { - entry->alg.u.auth = - ODP_AUTH_ALG_MD5_HMAC; - entry->icv_len = 12; - } else if (!strcmp(token, "sha256")) { - entry->alg.u.auth = - ODP_AUTH_ALG_SHA256_HMAC; - entry->icv_len = 16; - } else { - entry->alg.u.auth = ODP_AUTH_ALG_NULL; - } - } - break; - case 3: - entry->spi = strtol(token, NULL, 16); - break; - case 4: - parse_key_string(token, - &entry->key, - &entry->alg); - 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 (5 != pos) { - printf("ERROR: \"%s\" contains %d tokens, expected 5\n", - input, - pos); - free(local); - return -1; - } - - /* Add route to the list */ - sa_db->index++; - entry->next = sa_db->list; - sa_db->list = entry; - - free(local); - return 0; -} - -int create_tun_db_entry(char *input) -{ - int pos = 0; - char *local; - char *str; - char *save; - char *token; - tun_db_entry_t *entry = &tun_db->array[tun_db->index]; - - /* Verify we have a good entry */ - if (MAX_DB <= tun_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: - parse_ipv4_string(token, &entry->tun_src_ip, NULL); - break; - case 3: - parse_ipv4_string(token, &entry->tun_dst_ip, NULL); - break; - default: - printf("ERROR: extra token \"%s\" at position %d\n", - token, pos); - break; - } - pos++; - } - - /* Verify we parsed exactly the number of tokens we expected */ - if (4 != pos) { - printf("ERROR: \"%s\" contains %d tokens, expected 4\n", - input, - pos); - free(local); - return -1; - } - - /* Add route to the list */ - tun_db->index++; - entry->next = tun_db->list; - tun_db->list = entry; - - free(local); - return 0; -} - -tun_db_entry_t *find_tun_db_entry(uint32_t ip_src, - uint32_t ip_dst) -{ - tun_db_entry_t *entry = NULL; - - /* Scan all entries and return first match */ - for (entry = tun_db->list; NULL != entry; entry = entry->next) { - if (entry->src_ip != ip_src) - continue; - if (entry->dst_ip != ip_dst) - continue; - break; - } - return entry; -} - -void dump_sa_db(void) -{ - sa_db_entry_t *entry; - - printf("\n" - "Security association table\n" - "--------------------------\n"); - - for (entry = sa_db->list; NULL != entry; entry = entry->next) { - uint32_t idx; - char src_ip_str[MAX_STRING]; - char dst_ip_str[MAX_STRING]; - uint8_t *p = entry->key.data; - - - printf(" %s %s %s %X %d ", - entry->alg.cipher ? "esp" : "ah ", - ipv4_addr_str(src_ip_str, entry->src_ip), - ipv4_addr_str(dst_ip_str, entry->dst_ip), - entry->spi, - entry->alg.cipher ? - (int)entry->alg.u.cipher : - (int)entry->alg.u.auth); - - /* Brute force key display */ - for (idx = 0; idx < entry->key.length; idx++) - printf("%02X", *p++); - - printf("\n"); - } -} - -sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src, - ip_addr_range_t *dst, - odp_bool_t cipher) -{ - sa_db_entry_t *entry = NULL; - - /* Scan all entries and return first match */ - for (entry = sa_db->list; NULL != entry; entry = entry->next) { - if (cipher != entry->alg.cipher) - continue; - if (!match_ip_range(entry->src_ip, src)) - continue; - if (!match_ip_range(entry->dst_ip, dst)) - continue; - break; - } - return entry; -} - -void dump_tun_db(void) -{ - tun_db_entry_t *entry; - - printf("\n" - "Tunnel table\n" - "--------------------------\n"); - - for (entry = tun_db->list; NULL != entry; entry = entry->next) { - char src_ip_str[MAX_STRING]; - char dst_ip_str[MAX_STRING]; - char tun_src_ip_str[MAX_STRING]; - char tun_dst_ip_str[MAX_STRING]; - - printf(" %s:%s %s:%s ", - ipv4_addr_str(src_ip_str, entry->src_ip), - ipv4_addr_str(dst_ip_str, entry->dst_ip), - ipv4_addr_str(tun_src_ip_str, entry->tun_src_ip), - ipv4_addr_str(tun_dst_ip_str, entry->tun_dst_ip) - ); - - printf("\n"); - } -} diff --git a/example/ipsec/odp_ipsec_sa_db.h b/example/ipsec/odp_ipsec_sa_db.h deleted file mode 100644 index 729d98d56..000000000 --- a/example/ipsec/odp_ipsec_sa_db.h +++ /dev/null @@ -1,131 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_SA_DB_H_ -#define ODP_IPSEC_SA_DB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef enum sa_mode_s { - IPSEC_SA_MODE_TRANSPORT, - IPSEC_SA_MODE_TUNNEL -} sa_mode_t; -/** - * Security Association (SA) data base entry - */ -typedef struct sa_db_entry_s { - struct sa_db_entry_s *next; /**< Next entry on list */ - uint32_t src_ip; /**< Source IPv4 address */ - uint32_t dst_ip; /**< Desitnation IPv4 address */ - uint32_t spi; /**< Security Parameter Index */ - ipsec_alg_t alg; /**< Cipher/auth algorithm */ - ipsec_key_t key; /**< Cipher/auth key */ - uint32_t block_len; /**< Cipher block length */ - uint32_t iv_len; /**< Initialization Vector length */ - uint32_t icv_len; /**< Integrity Check Value length */ - sa_mode_t mode; /**< SA mode - transport/tun */ -} sa_db_entry_t; - -/** - * Security Association (SA) data base global structure - */ -typedef struct sa_db_s { - uint32_t index; /**< Index of next available entry */ - sa_db_entry_t *list; /**< List of active entries */ - sa_db_entry_t array[MAX_DB]; /**< Entry storage */ -} sa_db_t; - -/** Initialize SA database global control structure */ -void init_sa_db(void); - -/** - * Create an SA DB entry - * - * String is of the format "SrcIP:DstIP:Alg:SPI:Key" - * - * @param input Pointer to string describing SA - * @param cipher TRUE if cipher else FALSE for auth - * - * @return 0 if successful else -1 - */ -int create_sa_db_entry(char *input, odp_bool_t cipher); -/** - * Display the SA DB - */ -void dump_sa_db(void); - -/** - * Find a matching SA DB entry - * - * @param src Pointer to source subnet/range - * @param dst Pointer to destination subnet/range - * @param cipher TRUE if cipher else FALSE for auth - * - * @return pointer to SA DB entry else NULL - */ -sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src, - ip_addr_range_t *dst, - odp_bool_t cipher); - -/** - * Tunnel entry - */ -typedef struct tun_db_entry_s { - struct tun_db_entry_s *next; - uint32_t src_ip; /**< Inner Source IPv4 address */ - uint32_t dst_ip; /**< Inner Destination IPv4 address */ - uint32_t tun_src_ip; /**< Tunnel Source IPv4 address */ - uint32_t tun_dst_ip; /**< Tunnel Source IPv4 address */ -} tun_db_entry_t; - -/** - * Tunnel database - */ -typedef struct tun_db_s { - uint32_t index; /**< Index of next available entry */ - tun_db_entry_t *list; /**< List of active entries */ - tun_db_entry_t array[MAX_DB]; /**< Entry storage */ -} tun_db_t; - -/** Initialize tun database global control structure */ -void init_tun_db(void); - -/** - * Create an tunnel DB entry - * - * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp" - * - * @param input Pointer to string describing tun - * - * @return 0 if successful else -1 - */ -int create_tun_db_entry(char *input); - -/** - * Display the tun DB - */ -void dump_tun_db(void); - -/** - * Find a matching tun DB entry - * - * @param ip_src Inner source IP address - * @param ip_dst Inner destination IP address - * - * @return pointer to tun DB entry else NULL - */ -tun_db_entry_t *find_tun_db_entry(uint32_t ip_src, - uint32_t ip_dst); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/example/ipsec/odp_ipsec_sp_db.c b/example/ipsec/odp_ipsec_sp_db.c deleted file mode 100644 index 1e5820b47..000000000 --- a/example/ipsec/odp_ipsec_sp_db.c +++ /dev/null @@ -1,159 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* enable strtok */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include - -#include -#include - -#include - -/** Global pointer to sp db */ -sp_db_t *sp_db; - -void init_sp_db(void) -{ - odp_shm_t shm; - - shm = odp_shm_reserve("shm_sp_db", - sizeof(sp_db_t), - ODP_CACHE_LINE_SIZE, - 0); - - if (shm == ODP_SHM_INVALID) { - ODPH_ERR("Error: shared mem reserve failed.\n"); - exit(EXIT_FAILURE); - } - - sp_db = odp_shm_addr(shm); - - if (sp_db == NULL) { - ODPH_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(sp_db, 0, sizeof(*sp_db)); -} - -int create_sp_db_entry(char *input, odp_bool_t both_supported) -{ - int pos = 0; - char *local; - char *str; - char *save; - char *token; - sp_db_entry_t *entry = &sp_db->array[sp_db->index]; - - /* Verify we have a good entry */ - if (MAX_DB <= sp_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_subnet.addr, - &entry->src_subnet.mask); - break; - case 1: - parse_ipv4_string(token, - &entry->dst_subnet.addr, - &entry->dst_subnet.mask); - break; - case 2: - if (0 == strcmp(token, "in")) - entry->input = TRUE; - else - entry->input = FALSE; - break; - case 3: - if (0 == strcmp(token, "esp")) { - entry->esp = TRUE; - } else if (0 == strcmp(token, "ah")) { - entry->ah = TRUE; - } else if (0 == strcmp(token, "both")) { - entry->esp = TRUE; - entry->ah = TRUE; - } - break; - default: - printf("ERROR: extra token \"%s\" at position %d\n", - token, pos); - break; - } - - /* Advance to next position */ - pos++; - } - - /* Check if enabling both AH and ESP protocols is supported */ - if (!both_supported && (entry->ah && entry->esp)) { - printf("ERROR: enabling both AH and ESP is not supported\n"); - free(local); - return -1; - } - - /* Verify we parsed exactly the number of tokens we expected */ - if (4 != pos) { - printf("ERROR: \"%s\" contains %d tokens, expected 4\n", - input, - pos); - free(local); - return -1; - } - - /* Add route to the list */ - sp_db->index++; - entry->next = sp_db->list; - sp_db->list = entry; - - free(local); - return 0; -} - -void dump_sp_db_entry(sp_db_entry_t *entry) -{ - char src_subnet_str[MAX_STRING]; - char dst_subnet_str[MAX_STRING]; - - printf(" %s %s %s %s:%s\n", - ipv4_subnet_str(src_subnet_str, &entry->src_subnet), - ipv4_subnet_str(dst_subnet_str, &entry->dst_subnet), - entry->input ? "in" : "out", - entry->esp ? "esp" : "none", - entry->ah ? "ah" : "none"); -} - -void dump_sp_db(void) -{ - sp_db_entry_t *entry; - - printf("\n" - "Security policy table\n" - "---------------------\n"); - - for (entry = sp_db->list; NULL != entry; entry = entry->next) - dump_sp_db_entry(entry); -} diff --git a/example/ipsec/odp_ipsec_sp_db.h b/example/ipsec/odp_ipsec_sp_db.h deleted file mode 100644 index 878f3a7c4..000000000 --- a/example/ipsec/odp_ipsec_sp_db.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_SP_DB_H_ -#define ODP_IPSEC_SP_DB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * Security Policy (SP) data base entry - */ -typedef struct sp_db_entry_s { - struct sp_db_entry_s *next; /**< Next entry on list */ - ip_addr_range_t src_subnet; /**< Source IPv4 subnet/range */ - ip_addr_range_t dst_subnet; /**< Destination IPv4 subnet/range */ - odp_bool_t input; /**< Direction when applied */ - odp_bool_t esp; /**< Enable cipher (ESP) */ - odp_bool_t ah; /**< Enable authentication (AH) */ -} sp_db_entry_t; - -/** - * Security Policy (SP) data base global structure - */ -typedef struct sp_db_s { - uint32_t index; /**< Index of next available entry */ - sp_db_entry_t *list; /**< List of active entries */ - sp_db_entry_t array[MAX_DB]; /**< Entry storage */ -} sp_db_t; - -/** Global pointer to sp db */ -extern sp_db_t *sp_db; - -/** Initialize SP database global control structure */ -void init_sp_db(void); - -/** - * Create an SP DB entry - * - * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|[both])" - * - * @param input Pointer to a string describing SP - * @param both_supported Enabling both AH and ESP is supported - * - * @return 0 if successful else -1 - */ -int create_sp_db_entry(char *input, odp_bool_t both_supported); - -/** - * Display one SP DB entry - * - * @param entry Pointer to entry to display - */ -void dump_sp_db_entry(sp_db_entry_t *entry); - -/** - * Display the SP DB - */ -void dump_sp_db(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/example/ipsec/odp_ipsec_stream.c b/example/ipsec/odp_ipsec_stream.c deleted file mode 100644 index d689c6198..000000000 --- a/example/ipsec/odp_ipsec_stream.c +++ /dev/null @@ -1,678 +0,0 @@ -/* Copyright (c) 2014-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* enable strtok */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include - -#define STREAM_MAGIC 0xBABE01234567CAFE - -#define LOOP_DEQ_COUNT 32 /**< packets to dequeue at once */ - -/** - * Stream packet header - */ -typedef struct ODP_PACKED stream_pkt_hdr_s { - odp_u64be_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) -{ - odp_shm_t shm; - - shm = odp_shm_reserve("stream_db", - 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)); -} - -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; -} - -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); - - /* 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); - } -} - -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_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->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 = 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); - memset(data, 0, encrypt_len - payload_len); - data += encrypt_len - payload_len; - - 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(EVP_md5(), - entry->ah.key.data, - entry->ah.key.length, - (uint8_t *)ip, - auth_len, - hash, - NULL); - - memcpy(ah->icv, hash, 12); - } - - /* 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); - - /* 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) - 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]; - - /* 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, - 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 (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; -} diff --git a/example/ipsec/odp_ipsec_stream.h b/example/ipsec/odp_ipsec_stream.h deleted file mode 100644 index b32f1d7cb..000000000 --- a/example/ipsec/odp_ipsec_stream.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (c) 2014-2018, 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 */ - uint32_t length; /**< Packet payload length */ - uint32_t created; /**< Number successfully created */ - uint32_t verified; /**< Number successfully verified */ - struct { - const char *intf; /**< Input interface name */ - odp_pktio_t pktio; /**< Input PktI/O interface */ - 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 { - const char *intf; /**< Output interface name */ - odp_pktio_t pktio; /**< Output PktI/O interface */ - 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 - * @param max_len Maximum packet length - * - * @return packet else ODP_PACKET_INVALID - */ -odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, - uint8_t *dmac, - odp_pool_t pkt_pool, - uint32_t max_len); - -/** - * Verify an IPv4 packet received on a loop output queue - * - * @param stream Stream to verify the packet against - * @param pkt Packet to verify - * - * @return TRUE if packet verifies else FALSE - */ -odp_bool_t 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 removed and processed as if they had come from a normal - * packet interface. - * - * @return number of streams successfully processed - * @return <0 on failure - */ -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 - */ -odp_bool_t verify_stream_db_outputs(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/example/ipsec_api/odp_ipsec_fwd_db.c b/example/ipsec_api/odp_ipsec_fwd_db.c index 63b0d36d6..aba996aaf 120000 --- a/example/ipsec_api/odp_ipsec_fwd_db.c +++ b/example/ipsec_api/odp_ipsec_fwd_db.c @@ -1 +1 @@ -../ipsec/odp_ipsec_fwd_db.c \ No newline at end of file +../ipsec_crypto/odp_ipsec_fwd_db.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_fwd_db.h b/example/ipsec_api/odp_ipsec_fwd_db.h index 5a709f212..f9a8ab957 120000 --- a/example/ipsec_api/odp_ipsec_fwd_db.h +++ b/example/ipsec_api/odp_ipsec_fwd_db.h @@ -1 +1 @@ -../ipsec/odp_ipsec_fwd_db.h \ No newline at end of file +../ipsec_crypto/odp_ipsec_fwd_db.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_misc.h b/example/ipsec_api/odp_ipsec_misc.h index f1de214a4..7bb7de030 120000 --- a/example/ipsec_api/odp_ipsec_misc.h +++ b/example/ipsec_api/odp_ipsec_misc.h @@ -1 +1 @@ -../ipsec/odp_ipsec_misc.h \ No newline at end of file +../ipsec_crypto/odp_ipsec_misc.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_sa_db.c b/example/ipsec_api/odp_ipsec_sa_db.c index d9c593fa8..7ce1a5292 120000 --- a/example/ipsec_api/odp_ipsec_sa_db.c +++ b/example/ipsec_api/odp_ipsec_sa_db.c @@ -1 +1 @@ -../ipsec/odp_ipsec_sa_db.c \ No newline at end of file +../ipsec_crypto/odp_ipsec_sa_db.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_sa_db.h b/example/ipsec_api/odp_ipsec_sa_db.h index 57d50f3c2..9b022c202 120000 --- a/example/ipsec_api/odp_ipsec_sa_db.h +++ b/example/ipsec_api/odp_ipsec_sa_db.h @@ -1 +1 @@ -../ipsec/odp_ipsec_sa_db.h \ No newline at end of file +../ipsec_crypto/odp_ipsec_sa_db.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_sp_db.c b/example/ipsec_api/odp_ipsec_sp_db.c index c4f785fa6..c7bd160fa 120000 --- a/example/ipsec_api/odp_ipsec_sp_db.c +++ b/example/ipsec_api/odp_ipsec_sp_db.c @@ -1 +1 @@ -../ipsec/odp_ipsec_sp_db.c \ No newline at end of file +../ipsec_crypto/odp_ipsec_sp_db.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_sp_db.h b/example/ipsec_api/odp_ipsec_sp_db.h index e37f78432..26369e9bb 120000 --- a/example/ipsec_api/odp_ipsec_sp_db.h +++ b/example/ipsec_api/odp_ipsec_sp_db.h @@ -1 +1 @@ -../ipsec/odp_ipsec_sp_db.h \ No newline at end of file +../ipsec_crypto/odp_ipsec_sp_db.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_stream.c b/example/ipsec_api/odp_ipsec_stream.c index 4835150d1..57e25fe0e 120000 --- a/example/ipsec_api/odp_ipsec_stream.c +++ b/example/ipsec_api/odp_ipsec_stream.c @@ -1 +1 @@ -../ipsec/odp_ipsec_stream.c \ No newline at end of file +../ipsec_crypto/odp_ipsec_stream.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_stream.h b/example/ipsec_api/odp_ipsec_stream.h index 1cabba28c..6ad6700cc 120000 --- a/example/ipsec_api/odp_ipsec_stream.h +++ b/example/ipsec_api/odp_ipsec_stream.h @@ -1 +1 @@ -../ipsec/odp_ipsec_stream.h \ No newline at end of file +../ipsec_crypto/odp_ipsec_stream.h \ No newline at end of file diff --git a/example/ipsec_crypto/.gitignore b/example/ipsec_crypto/.gitignore new file mode 100644 index 000000000..2467edfd4 --- /dev/null +++ b/example/ipsec_crypto/.gitignore @@ -0,0 +1 @@ +odp_ipsec_crypto diff --git a/example/ipsec_crypto/Makefile.am b/example/ipsec_crypto/Makefile.am new file mode 100644 index 000000000..0de60cf89 --- /dev/null +++ b/example/ipsec_crypto/Makefile.am @@ -0,0 +1,58 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_ipsec_crypto + +dist_check_SCRIPTS = \ + odp_ipsec_crypto_run_ah_in.sh \ + odp_ipsec_crypto_run_ah_out.sh \ + odp_ipsec_crypto_run_both_in.sh \ + odp_ipsec_crypto_run_both_out.sh \ + odp_ipsec_crypto_run_esp_in.sh \ + odp_ipsec_crypto_run_esp_out.sh \ + odp_ipsec_crypto_run_live.sh \ + odp_ipsec_crypto_run_router.sh \ + odp_ipsec_crypto_run_simple.sh + +odp_ipsec_crypto_SOURCES = \ + odp_ipsec.c \ + odp_ipsec_sa_db.c \ + odp_ipsec_sp_db.c \ + odp_ipsec_fwd_db.c \ + odp_ipsec_cache.c \ + odp_ipsec_cache.h \ + odp_ipsec_fwd_db.h \ + odp_ipsec_misc.h \ + odp_ipsec_sa_db.h \ + odp_ipsec_sp_db.h + +if WITH_OPENSSL +odp_ipsec_crypto_SOURCES += \ + odp_ipsec_stream.c \ + odp_ipsec_stream.h + +AM_CPPFLAGS = $(OPENSSL_CPPFLAGS) +LDADD += $(OPENSSL_LIBS) + +else +AM_CPPFLAGS = -DNO_OPENSSL +endif + +# If building out-of-tree, make check will not copy the scripts and data to the +# $(builddir) assuming that all commands are run locally. However this prevents +# running tests on a remote target using LOG_COMPILER. +# So copy all script and data files explicitly here. +all-local: + if [ "x$(srcdir)" != "x$(builddir)" ]; then \ + for f in $(dist_check_SCRIPTS); do \ + if [ -e $(srcdir)/$$f ]; then \ + mkdir -p $(builddir)/$$(dirname $$f); \ + cp $(srcdir)/$$f $(builddir)/$$f; \ + fi \ + done \ + fi +clean-local: + if [ "x$(srcdir)" != "x$(builddir)" ]; then \ + for f in $(dist_check_SCRIPTS); do \ + rm -f $(builddir)/$$f; \ + done \ + fi diff --git a/example/ipsec_crypto/README b/example/ipsec_crypto/README new file mode 100644 index 000000000..9a3fdc4b9 --- /dev/null +++ b/example/ipsec_crypto/README @@ -0,0 +1,171 @@ +Copyright (c) 2014-2018, Linaro Limited +All rights reserved. + +SPDX-License-Identifier: BSD-3-Clause + +1. Intro + +The odp_ipsec_crypto example application demonstrates an IPsec implementation +using ODP crypto APIs. The application functions as a simple L3 IPv4 router +which supports IPsec 3DES cipher and HMAC-MD5 authentication in both the +transmit and receive directions. Note that only IPsec "transport" mode is +supported. + +2. Prerequisites + + 2.1 SSL development libraries + +Development has been done to this point with the openssl-devel libraries, +the makefile specifically links with "-lcrypto". + +3. Topology + +The following test topology was used for development. Each of the VMs +is running Fedora 32. Sanity testing consists of pinging VM2 from VM0 +such that the packets traverse VM1. Packets between VM1 and VM2 are +IPsec AH and ESP encapsulated. + + VM0 VM1 (UUT) VM2 ++------------+ +--------------+ +------------+ +| | (clear) | | (crypto) | | +| | subnet | | subnet | | +| p7p1 |<---------------->| p7p1 p8p1 |<---------------->| p7p1 | +| .2 | 192.168.111.0 | .1 .1 | 192.168.222.0 | .2 | +| | | | | | ++------------+ +--------------+ +------------+ + +4. VM configurations + + 4.1 VM0 configuration + +VM0 has the following interface configuration: + + cat /etc/sysconfig/network-scripts/ifcfg-p7p1 + DEVICE=p7p1 + HWADDR=08:00:27:76:B5:E0 + BOOTPROTO=static + IPADDR=192.168.111.2 + NETMASK=255.255.255.0 + ONBOOT=yes + +In addition, static ARP and IPv4 routes must be added on VM0: + + sudo ip route add 192.168.222.0/24 via 192.168.111.1 + sudo arp -s 192.168.111.1 08:00:27:04:BF:8C + + 4.2 VM1 configuration + +For the unit under test, IP forwarding and IP tables were disabled. + +VM1 has the following interface configurations: + + cat /etc/sysconfig/network-scripts/ifcfg-p7p1 + DEVICE=p7p1 + HWADDR=08:00:27:04:BF:8C + BOOTPROTO=static + IPADDR=192.168.111.1 + NETMASK=255.255.255.0 + ONBOOT=yes + + cat /etc/sysconfig/network-scripts/ifcfg-p8p1 + DEVICE=p8p1 + HWADDR=08:00:27:4C:55:CC + BOOTPROTO=static + IPADDR=192.168.222.1 + NETMASK=255.255.255.0 + ONBOOT=yes + +The application is launched on VM1 with the following command: + + sudo ./odp_ipsec_crypto -i p7p1,p8p1 \ + -r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ + -r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ + -p 192.168.111.0/24:192.168.222.0/24:out:both \ + -e 192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ + -a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ + -p 192.168.222.0/24:192.168.111.0/24:in:both \ + -e 192.168.222.2:192.168.111.2:3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ + -a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ + -c 2 -m 0 + + 4.3 VM2 configuration + +VM2 has the following interface configuration: + + cat /etc/sysconfig/network-scripts/ifcfg-p7p1 + DEVICE=p7p1 + HWADDR=08:00:27:F5:8B:DB + BOOTPROTO=static + IPADDR=192.168.222.2 + NETMASK=255.255.255.0 + ONBOOT=yes + +In addition, static ARP and IPv4 routes must be added on VM2: + + sudo ip route add 192.168.111.0/24 via 192.168.222.1 + sudo arp -s 192.168.222.1 08:00:27:4c:55:cc + +VM2 must be setup with an IPsec configuration complementing +the configuration used by the "odp_ipsec_crypto" application running +on VM1. The configuration is applied using "setkey" (provided by ipsec-tools +package). + +VM2 uses the following setkey configuration: + + cat setkey_vm2.conf + # Flush the SAD and SPD + flush; + spdflush; + + add 192.168.111.2 192.168.222.2 ah 0x200 -A hmac-md5 + 0xa731649644c5dee92cbd9c2e7e188ee6; + add 192.168.222.2 192.168.111.2 ah 0x300 -A hmac-md5 + 0x27f6d123d7077b361662fc6e451f65d8; + + add 192.168.111.2 192.168.222.2 esp 0x201 -E 3des-cbc + 0x656c8523255ccc23a66c1917aa0cf30991fce83532a4b224; + add 192.168.222.2 192.168.111.2 esp 0x301 -E 3des-cbc + 0xc966199f24d095f3990a320d749056401e82b26570320292; + + spdadd 192.168.111.2 192.168.222.2 any -P in ipsec + esp/transport//require + ah/transport//require; + + spdadd 192.168.222.2 192.168.111.2 any -P out ipsec + esp/transport//require + ah/transport//require; + +Apply the setkey configuration: + sudo setkey -f setkey_vm2.conf + +5. Sanity Test with Real Traffic + +Once all three VMs have been configured, static ARP and route entries added, +setkey configuration applied, and odp_ipsec_crypto application is running, VM0 +should be able to ping VM2 at the 192.168.222.2 address. + +At VM0 console issue the ping to VM2's address: + + sudo ping -c 2 -i 0.1 192.168.222.2 + PING 192.168.222.2 (192.168.222.2) 56(84) bytes of data. + 64 bytes from 192.168.222.2: icmp_req=1 ttl=64 time=33.9 ms + 64 bytes from 192.168.222.2: icmp_req=2 ttl=64 time=23.3 ms + +At VM2 console use tcpdump to observe IPsec packets: + + sudo tcpdump -nt -i p7p1 + tcpdump: verbose output suppressed, use -v or -vv for full protocol decode + listening on p7p1, link-type EN10MB (Ethernet), capture size 65535 bytes + + IP 192.168.111.2 > 192.168.222.2: AH(spi=0x00000200,seq=0x6): ESP(spi=0x00000201,seq=0x6), length 88 + IP 192.168.222.2 > 192.168.111.2: AH(spi=0x00000300,seq=0x7a): ESP(spi=0x00000301,seq=0x7a), length 88 + IP 192.168.111.2 > 192.168.222.2: AH(spi=0x00000200,seq=0x7): ESP(spi=0x00000201,seq=0x7), length 88 + IP 192.168.222.2 > 192.168.111.2: AH(spi=0x00000300,seq=0x7b): ESP(spi=0x00000301,seq=0x7b), length 88 + +6. Standalone Loopback Tests + +BASH batch files are now included to run several simple loopback tests that +do not require any packet IO. The scripts create internal "loopback" packet +interfaces. +Before running the example bash scripts add odp_ipsec_crypto to your PATH +export PATH=":$PATH" diff --git a/example/ipsec_crypto/odp_ipsec.c b/example/ipsec_crypto/odp_ipsec.c new file mode 100644 index 000000000..c4f34cbfa --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec.c @@ -0,0 +1,1658 @@ +/* Copyright (c) 2013-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * @example odp_example_ipsec.c ODP basic packet IO cross connect with IPsec test application + */ + +/* enable strtok */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef NO_OPENSSL +#include +#else +static void init_stream_db(void) {} +static void resolve_stream_db(void) {} +static int create_stream_db_inputs(void) +{ + return 0; +} + +static odp_bool_t verify_stream_db_outputs(void) +{ + return true; +} + +static int create_stream_db_entry(char *input ODP_UNUSED) +{ + return -1; +} +#endif + +/* maximum number of worker threads */ +#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1) + +#define MAX_POLL_QUEUES 256 + +/** + * Parsed command line application arguments + */ +typedef struct { + unsigned int cpu_count; + int if_count; /**< Number of interfaces to be used */ + char **if_names; /**< Array of pointers to interface names */ + crypto_api_mode_e mode; /**< Crypto API preferred mode */ + odp_pool_t pool; /**< Buffer pool for packet IO */ + char *if_str; /**< Storage for interface names */ +} appl_args_t; + +/** + * Grouping of both parsed CL args and global application data + */ +typedef struct { + /** Application (parsed) arguments */ + appl_args_t appl; + odp_shm_t shm; + odp_pool_t ctx_pool; + odp_pool_t out_pool; + odp_pool_t pkt_pool; + /** ATOMIC queue for IPsec sequence number assignment */ + odp_queue_t seqnumq; + /** ORDERED queue for per packet crypto API completion events */ + odp_queue_t completionq; + /** Synchronize threads before packet processing begins */ + odp_barrier_t sync_barrier; + odp_queue_t poll_queues[MAX_POLL_QUEUES]; + int num_polled_queues; + /* Stop workers if set to 1 */ + odp_atomic_u32_t exit_threads; +} global_data_t; + +/* helper funcs */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args); +static void print_info(char *progname, appl_args_t *appl_args); +static void usage(char *progname); + +/** + * Buffer pool for packet IO + */ +#define SHM_PKT_POOL_BUF_COUNT 1024 +#define SHM_PKT_POOL_BUF_SIZE 4096 +#define SHM_PKT_POOL_SIZE (SHM_PKT_POOL_BUF_COUNT * SHM_PKT_POOL_BUF_SIZE) + +/** + * Buffer pool for crypto session output packets + */ +#define SHM_OUT_POOL_BUF_COUNT 1024 +#define SHM_OUT_POOL_BUF_SIZE 4096 +#define SHM_OUT_POOL_SIZE (SHM_OUT_POOL_BUF_COUNT * SHM_OUT_POOL_BUF_SIZE) + +/** + * Packet processing states/steps + */ +typedef enum { + PKT_STATE_INPUT_VERIFY, /**< Verify IPv4 and ETH */ + PKT_STATE_IPSEC_IN_CLASSIFY, /**< Initiate input IPsec */ + PKT_STATE_IPSEC_IN_FINISH, /**< Finish input IPsec */ + PKT_STATE_ROUTE_LOOKUP, /**< Use DST IP to find output IF */ + PKT_STATE_IPSEC_OUT_CLASSIFY, /**< Intiate output IPsec */ + PKT_STATE_IPSEC_OUT_SEQ, /**< Assign IPsec sequence numbers */ + PKT_STATE_IPSEC_OUT_FINISH, /**< Finish output IPsec */ + PKT_STATE_TRANSMIT, /**< Send packet to output IF queue */ +} pkt_state_e; + +/** + * Packet processing result codes + */ +typedef enum { + PKT_CONTINUE, /**< No events posted, keep processing */ + PKT_POSTED, /**< Event posted, stop processing */ + PKT_DROP, /**< Reason to drop detected, stop processing */ + PKT_DONE /**< Finished with packet, stop processing */ +} pkt_disposition_e; + +/** + * Per packet IPsec processing context + */ +typedef struct { + uint8_t ip_tos; /**< Saved IP TOS value */ + uint16_t ip_frag_offset; /**< Saved IP flags value */ + uint8_t ip_ttl; /**< Saved IP TTL value */ + int hdr_len; /**< Length of IPsec headers */ + int trl_len; /**< Length of IPsec trailers */ + uint16_t tun_hdr_offset; /**< Offset of tunnel header from + buffer start */ + uint16_t ah_offset; /**< Offset of AH header from buffer start */ + uint16_t esp_offset; /**< Offset of ESP header from buffer start */ + + /* Input only */ + uint32_t src_ip; /**< SA source IP address */ + uint32_t dst_ip; /**< SA dest IP address */ + + /* Output only */ + odp_crypto_packet_op_param_t params; /**< Parameters for crypto call */ + uint32_t *ah_seq; /**< AH sequence number location */ + uint32_t *esp_seq; /**< ESP sequence number location */ + uint16_t *tun_hdr_id; /**< Tunnel header ID > */ +} ipsec_ctx_t; + +/** + * Per packet processing context + */ +typedef struct { + odp_buffer_t buffer; /**< Buffer for context */ + pkt_state_e state; /**< Next processing step */ + ipsec_ctx_t ipsec; /**< IPsec specific context */ + odp_pktout_queue_t pktout; /**< Packet output queue */ +} pkt_ctx_t; + +#define SHM_CTX_POOL_BUF_SIZE (sizeof(pkt_ctx_t)) +#define SHM_CTX_POOL_BUF_COUNT (SHM_PKT_POOL_BUF_COUNT + SHM_OUT_POOL_BUF_COUNT) +#define SHM_CTX_POOL_SIZE (SHM_CTX_POOL_BUF_COUNT * SHM_CTX_POOL_BUF_SIZE) + +static global_data_t *global; + +static void sig_handler(int signo ODP_UNUSED) +{ + if (global == NULL) + return; + odp_atomic_store_u32(&global->exit_threads, 1); +} + +/** + * Get per packet processing context from packet buffer + * + * @param pkt Packet + * + * @return pointer to context area + */ +static +pkt_ctx_t *get_pkt_ctx_from_pkt(odp_packet_t pkt) +{ + return (pkt_ctx_t *)odp_packet_user_ptr(pkt); +} + +/** + * Allocate per packet processing context and associate it with + * packet buffer + * + * @param pkt Packet + * + * @return pointer to context area + */ +static +pkt_ctx_t *alloc_pkt_ctx(odp_packet_t pkt) +{ + odp_buffer_t ctx_buf = odp_buffer_alloc(global->ctx_pool); + pkt_ctx_t *ctx; + + if (odp_unlikely(ODP_BUFFER_INVALID == ctx_buf)) + return NULL; + + ctx = odp_buffer_addr(ctx_buf); + memset(ctx, 0, sizeof(*ctx)); + ctx->buffer = ctx_buf; + odp_packet_user_ptr_set(pkt, ctx); + + return ctx; +} + +/** + * Release per packet resources + * + * @param ctx Packet context + */ +static +void free_pkt_ctx(pkt_ctx_t *ctx) +{ + odp_buffer_free(ctx->buffer); +} + +/** + * Example supports either polling queues or using odp_schedule + */ +typedef odp_queue_t (*queue_create_func_t) + (const char *, const odp_queue_param_t *); +typedef odp_event_t (*schedule_func_t) (odp_queue_t *); + +static queue_create_func_t queue_create; +static schedule_func_t schedule_fn; + +/** + * odp_queue_create wrapper to enable polling versus scheduling + */ +static +odp_queue_t polled_odp_queue_create(const char *name, + const odp_queue_param_t *param) +{ + odp_queue_t my_queue; + odp_queue_param_t qp; + odp_queue_type_t type; + + odp_queue_param_init(&qp); + if (param) + memcpy(&qp, param, sizeof(odp_queue_param_t)); + + type = qp.type; + + if (ODP_QUEUE_TYPE_SCHED == type) { + printf("%s: change %s to PLAIN\n", __func__, name); + qp.type = ODP_QUEUE_TYPE_PLAIN; + } + + my_queue = odp_queue_create(name, &qp); + + if (ODP_QUEUE_TYPE_SCHED == type) { + global->poll_queues[global->num_polled_queues++] = my_queue; + printf("%s: adding %"PRIu64"\n", __func__, + odp_queue_to_u64(my_queue)); + } + + return my_queue; +} + +static inline +odp_event_t odp_schedule_cb(odp_queue_t *from) +{ + return odp_schedule(from, ODP_SCHED_NO_WAIT); +} + +/** + * odp_schedule replacement to poll queues versus using ODP scheduler + */ +static +odp_event_t polled_odp_schedule_cb(odp_queue_t *from) +{ + int idx = 0; + + while (idx < global->num_polled_queues) { + odp_queue_t queue = global->poll_queues[idx++]; + odp_event_t ev; + + ev = odp_queue_deq(queue); + + if (ODP_EVENT_INVALID != ev) { + *from = queue; + return ev; + } + } + + *from = ODP_QUEUE_INVALID; + return ODP_EVENT_INVALID; +} + +/** + * IPsec pre argument processing intialization + */ +static +void ipsec_init_pre(void) +{ + odp_queue_param_t qparam; + odp_pool_param_t params; + + /* + * Create queues + * + * - completion queue (should eventually be ORDERED) + * - sequence number queue (must be ATOMIC) + */ + odp_queue_param_init(&qparam); + qparam.type = ODP_QUEUE_TYPE_SCHED; + qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; + qparam.sched.group = ODP_SCHED_GROUP_ALL; + + global->completionq = queue_create("completion", &qparam); + if (ODP_QUEUE_INVALID == global->completionq) { + ODPH_ERR("Error: completion queue creation failed\n"); + exit(EXIT_FAILURE); + } + + qparam.type = ODP_QUEUE_TYPE_SCHED; + qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; + qparam.sched.group = ODP_SCHED_GROUP_ALL; + + global->seqnumq = queue_create("seqnum", &qparam); + if (ODP_QUEUE_INVALID == global->seqnumq) { + ODPH_ERR("Error: sequence number queue creation failed\n"); + exit(EXIT_FAILURE); + } + + /* Create output buffer pool */ + odp_pool_param_init(¶ms); + params.pkt.seg_len = SHM_OUT_POOL_BUF_SIZE; + params.pkt.len = SHM_OUT_POOL_BUF_SIZE; + params.pkt.num = SHM_PKT_POOL_BUF_COUNT; + params.type = ODP_POOL_PACKET; + + global->out_pool = odp_pool_create("out_pool", ¶ms); + + if (ODP_POOL_INVALID == global->out_pool) { + ODPH_ERR("Error: message pool create failed.\n"); + exit(EXIT_FAILURE); + } + + /* Initialize our data bases */ + init_sp_db(); + init_sa_db(); + init_tun_db(); + init_ipsec_cache(); +} + +/** + * IPsec post argument processing intialization + * + * Resolve SP DB with SA DB and create corresponding IPsec cache entries + * + * @param api_mode Mode to use when invoking per packet crypto API + */ +static +void ipsec_init_post(crypto_api_mode_e api_mode) +{ + sp_db_entry_t *entry; + + /* Attempt to find appropriate SA for each SP */ + for (entry = sp_db->list; NULL != entry; entry = entry->next) { + sa_db_entry_t *cipher_sa = NULL; + sa_db_entry_t *auth_sa = NULL; + tun_db_entry_t *tun = NULL; + + if (entry->esp) { + cipher_sa = find_sa_db_entry(&entry->src_subnet, + &entry->dst_subnet, + 1); + tun = find_tun_db_entry(cipher_sa->src_ip, + cipher_sa->dst_ip); + } + if (entry->ah) { + auth_sa = find_sa_db_entry(&entry->src_subnet, + &entry->dst_subnet, + 0); + tun = find_tun_db_entry(auth_sa->src_ip, + auth_sa->dst_ip); + } + + if (cipher_sa || auth_sa) { + if (create_ipsec_cache_entry(cipher_sa, + auth_sa, + tun, + api_mode, + entry->input, + global->completionq, + global->out_pool)) { + ODPH_ERR("Error: IPSec cache entry failed.\n" + ); + exit(EXIT_FAILURE); + } + } else { + printf(" WARNING: SA not found for SP\n"); + dump_sp_db_entry(entry); + } + } +} + +#ifndef NO_OPENSSL +static +int check_stream_db_out(const char *intf) +{ + 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) { + if (!strcmp(stream->output.intf, intf)) + return 1; + } + + return 0; +} +#else +static +int check_stream_db_out(const char *intf ODP_UNUSED) +{ + return 0; +} +#endif + +/** + * Initialize interface + * + * Initialize ODP pktio and queues, query MAC address and update + * forwarding database. + * + * @param intf Interface name string + */ +static +void initialize_intf(char *intf) +{ + odp_pktio_t pktio; + odp_pktout_queue_t pktout; + odp_queue_t inq; + int ret; + uint8_t src_mac[ODPH_ETHADDR_LEN]; + char src_mac_str[MAX_STRING]; + odp_pktio_param_t pktio_param; + odp_pktin_queue_param_t pktin_param; + + odp_pktio_param_init(&pktio_param); + + if (getenv("ODP_IPSEC_USE_POLL_QUEUES") || + check_stream_db_out(intf)) + pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE; + else + pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; + + /* + * Open a packet IO instance for thread and get default output queue + */ + pktio = odp_pktio_open(intf, global->pkt_pool, &pktio_param); + if (ODP_PKTIO_INVALID == pktio) { + ODPH_ERR("Error: pktio create failed for %s\n", intf); + exit(EXIT_FAILURE); + } + + odp_pktin_queue_param_init(&pktin_param); + pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC; + + if (odp_pktin_queue_config(pktio, &pktin_param)) { + ODPH_ERR("Error: pktin config failed for %s\n", intf); + exit(EXIT_FAILURE); + } + + if (odp_pktout_queue_config(pktio, NULL)) { + ODPH_ERR("Error: pktout config failed for %s\n", intf); + exit(EXIT_FAILURE); + } + + if (odp_pktin_event_queue(pktio, &inq, 1) != 1) { + ODPH_ERR("Error: failed to get input queue for %s\n", intf); + exit(EXIT_FAILURE); + } + + if (odp_pktout_queue(pktio, &pktout, 1) != 1) { + ODPH_ERR("Error: failed to get pktout queue for %s\n", intf); + exit(EXIT_FAILURE); + } + + ret = odp_pktio_start(pktio); + if (ret) { + ODPH_ERR("Error: unable to start %s\n", intf); + exit(EXIT_FAILURE); + } + + /* Read the source MAC address for this interface */ + ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac)); + if (ret <= 0) { + ODPH_ERR("Error: failed during MAC address get for %s\n", intf); + exit(EXIT_FAILURE); + } + + printf("Created pktio:%02" PRIu64 ", queue mode (ATOMIC queues)\n" + " default pktio%02" PRIu64 "-INPUT queue:%" PRIu64 "\n" + " source mac address %s\n", + odp_pktio_to_u64(pktio), odp_pktio_to_u64(pktio), + odp_queue_to_u64(inq), + mac_addr_str(src_mac_str, src_mac)); + + /* Resolve any routes using this interface for output */ + resolve_fwd_db(intf, pktio, pktout, src_mac); +} + +/** + * Packet Processing - Input verification + * + * @param pkt Packet to inspect + * @param ctx Packet process context (not used) + * + * @return PKT_CONTINUE if good, supported packet else PKT_DROP + */ +static +pkt_disposition_e do_input_verify(odp_packet_t pkt, + pkt_ctx_t *ctx ODP_UNUSED) +{ + if (odp_unlikely(odp_packet_has_error(pkt))) + return PKT_DROP; + + if (!odp_packet_has_eth(pkt)) + return PKT_DROP; + + if (!odp_packet_has_ipv4(pkt)) + return PKT_DROP; + + return PKT_CONTINUE; +} + +/** + * Packet Processing - Route lookup in forwarding database + * + * @param pkt Packet to route + * @param ctx Packet process context + * + * @return PKT_CONTINUE if route found else PKT_DROP + */ +static +pkt_disposition_e do_route_fwd_db(odp_packet_t pkt, pkt_ctx_t *ctx) +{ + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); + fwd_db_entry_t *entry; + + entry = find_fwd_db_entry(odp_be_to_cpu_32(ip->dst_addr)); + + if (entry) { + odph_ethhdr_t *eth = + (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL); + + memcpy(ð->dst, entry->dst_mac, ODPH_ETHADDR_LEN); + memcpy(ð->src, entry->src_mac, ODPH_ETHADDR_LEN); + ctx->pktout = entry->pktout; + + return PKT_CONTINUE; + } + + return PKT_DROP; +} + +/** + * Packet Processing - Input IPsec packet classification + * + * Verify the received packet has IPsec headers and a match + * in the IPsec cache, if so issue crypto request else skip + * input crypto. + * + * @param pkt Packet to classify + * @param ctx Packet process context + * @param skip Pointer to return "skip" indication + * + * @return PKT_CONTINUE if done else PKT_POSTED + */ +static +pkt_disposition_e do_ipsec_in_classify(odp_packet_t *pkt, + pkt_ctx_t *ctx, + odp_bool_t *skip) +{ + uint8_t *buf = odp_packet_data(*pkt); + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*pkt, NULL); + int hdr_len; + odph_ahhdr_t *ah = NULL; + odph_esphdr_t *esp = NULL; + ipsec_cache_entry_t *entry; + odp_crypto_packet_op_param_t params; + odp_packet_t out_pkt; + + /* Default to skip IPsec */ + *skip = TRUE; + + /* Check IP header for IPSec protocols and look it up */ + hdr_len = locate_ipsec_headers(ip, &ah, &esp); + if (!ah && !esp) + return PKT_CONTINUE; + entry = find_ipsec_cache_entry_in(odp_be_to_cpu_32(ip->src_addr), + odp_be_to_cpu_32(ip->dst_addr), + ah, + esp); + if (!entry) + return PKT_CONTINUE; + + /* Account for configured ESP IV length in packet */ + hdr_len += entry->esp.iv_len; + + /* Initialize parameters block */ + memset(¶ms, 0, sizeof(params)); + params.session = entry->state.session; + out_pkt = entry->in_place ? *pkt : ODP_PACKET_INVALID; + + /*Save everything to context */ + ctx->ipsec.ip_tos = ip->tos; + ctx->ipsec.ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset); + ctx->ipsec.ip_ttl = ip->ttl; + ctx->ipsec.ah_offset = ah ? ((uint8_t *)ah) - buf : 0; + ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0; + ctx->ipsec.hdr_len = hdr_len; + ctx->ipsec.trl_len = 0; + ctx->ipsec.src_ip = entry->src_ip; + ctx->ipsec.dst_ip = entry->dst_ip; + + /*If authenticating, zero the mutable fields build the request */ + if (ah) { + ip->chksum = 0; + ip->tos = 0; + ip->frag_offset = 0; + ip->ttl = 0; + + params.auth_range.offset = ((uint8_t *)ip) - buf; + params.auth_range.length = odp_be_to_cpu_16(ip->tot_len); + params.hash_result_offset = ah->icv - buf; + } + + /* If deciphering build request */ + if (esp) { + params.cipher_range.offset = ipv4_data_p(ip) + hdr_len - buf; + params.cipher_range.length = ipv4_data_len(ip) - hdr_len; + params.cipher_iv_ptr = esp->iv; + } + + /* Issue crypto request */ + *skip = FALSE; + ctx->state = PKT_STATE_IPSEC_IN_FINISH; + if (entry->async) { + if (odp_crypto_op_enq(pkt, &out_pkt, ¶ms, 1) != 1) { + ODPH_ERR("Error: odp_crypto_op_enq() failed\n"); + exit(EXIT_FAILURE); + } + return PKT_POSTED; + } + + if (odp_crypto_op(pkt, &out_pkt, ¶ms, 1) != 1) { + ODPH_ERR("Error: odp_crypto_op() failed\n"); + exit(EXIT_FAILURE); + } + *pkt = out_pkt; + + return PKT_CONTINUE; +} + +/** + * Packet Processing - Input IPsec packet processing cleanup + * + * @param pkt Packet to handle + * @param ctx Packet process context + * + * @return PKT_CONTINUE if successful else PKT_DROP + */ +static +pkt_disposition_e do_ipsec_in_finish(odp_packet_t pkt, + pkt_ctx_t *ctx) +{ + odph_ipv4hdr_t *ip; + odp_crypto_packet_result_t result; + int hdr_len = ctx->ipsec.hdr_len; + int trl_len = 0; + + odp_crypto_result(&result, pkt); + + /* Check crypto result */ + if (!result.ok) { + if (!is_crypto_op_status_ok(&result.cipher_status)) + return PKT_DROP; + if (!is_crypto_op_status_ok(&result.auth_status)) + return PKT_DROP; + } + ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); + + /* + * Finish auth + */ + if (ctx->ipsec.ah_offset) { + uint8_t *buf = odp_packet_data(pkt); + odph_ahhdr_t *ah; + + ah = (odph_ahhdr_t *)(ctx->ipsec.ah_offset + buf); + ip->proto = ah->next_header; + } + + /* + * Finish cipher by finding ESP trailer and processing + * + * NOTE: ESP authentication ICV not supported + */ + if (ctx->ipsec.esp_offset) { + uint8_t *eop = (uint8_t *)(ip) + odp_be_to_cpu_16(ip->tot_len); + odph_esptrl_t *esp_t = (odph_esptrl_t *)(eop) - 1; + + ip->proto = esp_t->next_header; + trl_len += esp_t->pad_len + sizeof(*esp_t); + } + + /* We have a tunneled IPv4 packet */ + if (ip->proto == ODPH_IPV4) { + odp_packet_pull_head(pkt, sizeof(*ip) + hdr_len); + odp_packet_pull_tail(pkt, trl_len); + odph_ethhdr_t *eth; + + eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL); + eth->type = ODPH_ETHTYPE_IPV4; + ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); + + /* Check inbound policy */ + if ((ip->src_addr != ctx->ipsec.src_ip || + ip->dst_addr != ctx->ipsec.dst_ip)) + return PKT_DROP; + + return PKT_CONTINUE; + } + + /* Finalize the IPv4 header */ + ipv4_adjust_len(ip, -(hdr_len + trl_len)); + ip->ttl = ctx->ipsec.ip_ttl; + ip->tos = ctx->ipsec.ip_tos; + ip->frag_offset = odp_cpu_to_be_16(ctx->ipsec.ip_frag_offset); + ip->chksum = 0; + odph_ipv4_csum_update(pkt); + + /* Correct the packet length and move payload into position */ + memmove(ipv4_data_p(ip), + ipv4_data_p(ip) + hdr_len, + odp_be_to_cpu_16(ip->tot_len)); + odp_packet_pull_tail(pkt, hdr_len + trl_len); + + /* Fall through to next state */ + return PKT_CONTINUE; +} + +/** + * Packet Processing - Output IPsec packet classification + * + * Verify the outbound packet has a match in the IPsec cache, + * if so issue prepend IPsec headers and prepare parameters + * for crypto API call. Post the packet to ATOMIC queue so + * that sequence numbers can be applied in packet order as + * the next processing step. + * + * @param pkt Packet to classify + * @param ctx Packet process context + * @param skip Pointer to return "skip" indication + * + * @return PKT_CONTINUE if done else PKT_POSTED + */ +static +pkt_disposition_e do_ipsec_out_classify(odp_packet_t pkt, + pkt_ctx_t *ctx, + odp_bool_t *skip) +{ + uint8_t *buf = odp_packet_data(pkt); + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); + uint16_t ip_data_len = ipv4_data_len(ip); + uint8_t *ip_data = ipv4_data_p(ip); + ipsec_cache_entry_t *entry; + odp_crypto_packet_op_param_t params; + int hdr_len = 0; + int trl_len = 0; + odph_ahhdr_t *ah = NULL; + odph_esphdr_t *esp = NULL; + + /* Default to skip IPsec */ + *skip = TRUE; + + /* Find record */ + entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr), + odp_be_to_cpu_32(ip->dst_addr), + ip->proto); + if (!entry) + return PKT_CONTINUE; + + /* Save IPv4 stuff */ + ctx->ipsec.ip_tos = ip->tos; + ctx->ipsec.ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset); + ctx->ipsec.ip_ttl = ip->ttl; + + /* Initialize parameters block */ + memset(¶ms, 0, sizeof(params)); + params.session = entry->state.session; + + if (entry->mode == IPSEC_SA_MODE_TUNNEL) { + hdr_len += sizeof(odph_ipv4hdr_t); + ip_data = (uint8_t *)ip; + ip_data_len += sizeof(odph_ipv4hdr_t); + } + /* Compute ah and esp, determine length of headers, move the data */ + if (entry->ah.alg) { + ah = (odph_ahhdr_t *)(ip_data + hdr_len); + hdr_len += sizeof(odph_ahhdr_t); + hdr_len += entry->ah.icv_len; + } + if (entry->esp.alg) { + esp = (odph_esphdr_t *)(ip_data + hdr_len); + hdr_len += sizeof(odph_esphdr_t); + hdr_len += entry->esp.iv_len; + } + memmove(ip_data + hdr_len, ip_data, ip_data_len); + ip_data += hdr_len; + + /* update outer header in tunnel mode */ + if (entry->mode == IPSEC_SA_MODE_TUNNEL) { + /* tunnel addresses */ + ip->src_addr = odp_cpu_to_be_32(entry->tun_src_ip); + ip->dst_addr = odp_cpu_to_be_32(entry->tun_dst_ip); + } + + /* For cipher, compute encrypt length, build headers and request */ + if (esp) { + uint32_t encrypt_len; + odph_esptrl_t *esp_t; + + encrypt_len = ESP_ENCODE_LEN(ip_data_len + + sizeof(*esp_t), + entry->esp.block_len); + trl_len = encrypt_len - ip_data_len; + + esp->spi = odp_cpu_to_be_32(entry->esp.spi); + memcpy(esp + 1, entry->state.iv, entry->esp.iv_len); + + esp_t = (odph_esptrl_t *)(ip_data + encrypt_len) - 1; + esp_t->pad_len = trl_len - sizeof(*esp_t); + if (entry->mode == IPSEC_SA_MODE_TUNNEL) + esp_t->next_header = ODPH_IPV4; + else + esp_t->next_header = ip->proto; + ip->proto = ODPH_IPPROTO_ESP; + + params.cipher_range.offset = ip_data - buf; + params.cipher_range.length = encrypt_len; + } + + /* For authentication, build header clear mutables and build request */ + if (ah) { + memset(ah, 0, sizeof(*ah) + entry->ah.icv_len); + ah->spi = odp_cpu_to_be_32(entry->ah.spi); + ah->ah_len = 1 + (entry->ah.icv_len / 4); + if (entry->mode == IPSEC_SA_MODE_TUNNEL && !esp) + ah->next_header = ODPH_IPV4; + else + ah->next_header = ip->proto; + ip->proto = ODPH_IPPROTO_AH; + + ip->chksum = 0; + ip->tos = 0; + ip->frag_offset = 0; + ip->ttl = 0; + + params.auth_range.offset = ((uint8_t *)ip) - buf; + params.auth_range.length = + odp_be_to_cpu_16(ip->tot_len) + (hdr_len + trl_len); + params.hash_result_offset = ah->icv - buf; + } + + /* Set IPv4 length before authentication */ + ipv4_adjust_len(ip, hdr_len + trl_len); + if (!odp_packet_push_tail(pkt, hdr_len + trl_len)) + return PKT_DROP; + + /* Save remaining context */ + ctx->ipsec.hdr_len = hdr_len; + ctx->ipsec.trl_len = trl_len; + ctx->ipsec.ah_offset = ah ? ((uint8_t *)ah) - buf : 0; + ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0; + ctx->ipsec.tun_hdr_offset = (entry->mode == IPSEC_SA_MODE_TUNNEL) ? + ((uint8_t *)ip - buf) : 0; + ctx->ipsec.ah_seq = &entry->state.ah_seq; + ctx->ipsec.esp_seq = &entry->state.esp_seq; + ctx->ipsec.tun_hdr_id = &entry->state.tun_hdr_id; + memcpy(&ctx->ipsec.params, ¶ms, sizeof(params)); + + *skip = FALSE; + + return PKT_POSTED; +} + +/** + * Packet Processing - Output IPsec packet sequence number assignment + * + * Assign the necessary sequence numbers and then issue the crypto API call + * + * @param pkt Packet to handle + * @param ctx Packet process context + * + * @return PKT_CONTINUE if done else PKT_POSTED + */ +static +pkt_disposition_e do_ipsec_out_seq(odp_packet_t *pkt, + pkt_ctx_t *ctx) +{ + uint8_t *buf = odp_packet_data(*pkt); + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*pkt, NULL); + odp_packet_t out_pkt; + ipsec_cache_entry_t *entry; + + entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr), + odp_be_to_cpu_32(ip->dst_addr), + ip->proto); + if (!entry) + return PKT_DROP; + + /* We were dispatched from atomic queue, assign sequence numbers */ + if (ctx->ipsec.ah_offset) { + odph_ahhdr_t *ah; + + ah = (odph_ahhdr_t *)(ctx->ipsec.ah_offset + buf); + ah->seq_no = odp_cpu_to_be_32((*ctx->ipsec.ah_seq)++); + } + if (ctx->ipsec.esp_offset) { + odph_esphdr_t *esp; + + esp = (odph_esphdr_t *)(ctx->ipsec.esp_offset + buf); + esp->seq_no = odp_cpu_to_be_32((*ctx->ipsec.esp_seq)++); + } + if (ctx->ipsec.tun_hdr_offset) { + odph_ipv4hdr_t *ip; + int ret; + + ip = (odph_ipv4hdr_t *)(ctx->ipsec.tun_hdr_offset + buf); + ip->id = odp_cpu_to_be_16((*ctx->ipsec.tun_hdr_id)++); + if (!ip->id) { + /* re-init tunnel hdr id */ + ret = odp_random_data((uint8_t *)ctx->ipsec.tun_hdr_id, + sizeof(*ctx->ipsec.tun_hdr_id), + 1); + if (ret != sizeof(*ctx->ipsec.tun_hdr_id)) { + ODPH_ERR("Error: Not enough random data\n"); + exit(EXIT_FAILURE); + } + } + } + + out_pkt = entry->in_place ? *pkt : ODP_PACKET_INVALID; + + /* Issue crypto request */ + if (entry->async) { + if (odp_crypto_op_enq(pkt, &out_pkt, + &ctx->ipsec.params, 1) != 1) { + ODPH_ERR("Error: odp_crypto_op_enq() failed\n"); + exit(EXIT_FAILURE); + } + return PKT_POSTED; + } + + if (odp_crypto_op(pkt, &out_pkt, &ctx->ipsec.params, 1) != 1) { + ODPH_ERR("Error: odp_crypto_op() failed\n"); + exit(EXIT_FAILURE); + } + *pkt = out_pkt; + + return PKT_CONTINUE; +} + +/** + * Packet Processing - Output IPsec packet processing cleanup + * + * @param pkt Packet to handle + * @param ctx Packet process context + * + * @return PKT_CONTINUE if successful else PKT_DROP + */ +static +pkt_disposition_e do_ipsec_out_finish(odp_packet_t pkt, + pkt_ctx_t *ctx) +{ + odph_ipv4hdr_t *ip; + odp_crypto_packet_result_t result; + + odp_crypto_result(&result, pkt); + + /* Check crypto result */ + if (!result.ok) { + if (!is_crypto_op_status_ok(&result.cipher_status)) + return PKT_DROP; + if (!is_crypto_op_status_ok(&result.auth_status)) + return PKT_DROP; + } + ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); + + /* Finalize the IPv4 header */ + ip->ttl = ctx->ipsec.ip_ttl; + ip->tos = ctx->ipsec.ip_tos; + ip->frag_offset = odp_cpu_to_be_16(ctx->ipsec.ip_frag_offset); + ip->chksum = 0; + odph_ipv4_csum_update(pkt); + + /* Fall through to next state */ + return PKT_CONTINUE; +} + +/** + * Packet IO worker thread + * + * Loop calling odp_schedule to obtain packets from one of three sources, + * and continue processing the packet based on the state stored in its + * per packet context. + * + * - Input interfaces (i.e. new work) + * - Sequence number assignment queue + * - Per packet crypto API completion queue + * + * @param arg Required by "odph_odpthreads_create", unused + * + * @return NULL (should never return) + */ +static +int pktio_thread(void *arg ODP_UNUSED) +{ + int thr; + odp_packet_t pkt; + odp_event_t ev; + unsigned long pkt_cnt = 0; + + thr = odp_thread_id(); + + printf("Pktio thread [%02i] starts\n", thr); + + odp_barrier_wait(&global->sync_barrier); + + /* Loop packets */ + while (!odp_atomic_load_u32(&global->exit_threads)) { + pkt_disposition_e rc; + pkt_ctx_t *ctx; + odp_queue_t dispatchq; + odp_event_subtype_t subtype; + + /* Use schedule to get event from any input queue */ + ev = schedule_fn(&dispatchq); + + if (ev == ODP_EVENT_INVALID) + continue; + + /* Determine new work versus completion or sequence number */ + if (ODP_EVENT_PACKET == odp_event_types(ev, &subtype)) { + pkt = odp_packet_from_event(ev); + if (global->seqnumq == dispatchq || + global->completionq == dispatchq) { + ctx = get_pkt_ctx_from_pkt(pkt); + } else { + ctx = alloc_pkt_ctx(pkt); + if (!ctx) { + odp_packet_free(pkt); + continue; + } + ctx->state = PKT_STATE_INPUT_VERIFY; + } + } else { + ODPH_ERR("Error: Bad event type\n"); + exit(EXIT_FAILURE); + } + + /* + * We now have a packet and its associated context. Loop here + * executing processing based on the current state value stored + * in the context as long as the processing return code + * indicates PKT_CONTINUE. + * + * For other return codes: + * + * o PKT_DONE - finished with the packet + * o PKT_DROP - something incorrect about the packet, drop it + * o PKT_POSTED - packet/event has been queued for later + */ + do { + odp_bool_t skip = FALSE; + + switch (ctx->state) { + case PKT_STATE_INPUT_VERIFY: + + rc = do_input_verify(pkt, ctx); + ctx->state = PKT_STATE_IPSEC_IN_CLASSIFY; + break; + + case PKT_STATE_IPSEC_IN_CLASSIFY: + + ctx->state = PKT_STATE_ROUTE_LOOKUP; + rc = do_ipsec_in_classify(&pkt, + ctx, + &skip); + break; + + case PKT_STATE_IPSEC_IN_FINISH: + + rc = do_ipsec_in_finish(pkt, ctx); + ctx->state = PKT_STATE_ROUTE_LOOKUP; + break; + + case PKT_STATE_ROUTE_LOOKUP: + + rc = do_route_fwd_db(pkt, ctx); + ctx->state = PKT_STATE_IPSEC_OUT_CLASSIFY; + break; + + case PKT_STATE_IPSEC_OUT_CLASSIFY: + + rc = do_ipsec_out_classify(pkt, + ctx, + &skip); + if (odp_unlikely(skip)) { + ctx->state = PKT_STATE_TRANSMIT; + } else { + ctx->state = PKT_STATE_IPSEC_OUT_SEQ; + if (odp_queue_enq(global->seqnumq, ev)) + rc = PKT_DROP; + } + break; + + case PKT_STATE_IPSEC_OUT_SEQ: + + ctx->state = PKT_STATE_IPSEC_OUT_FINISH; + rc = do_ipsec_out_seq(&pkt, ctx); + break; + + case PKT_STATE_IPSEC_OUT_FINISH: + + rc = do_ipsec_out_finish(pkt, ctx); + ctx->state = PKT_STATE_TRANSMIT; + break; + + case PKT_STATE_TRANSMIT: + + if (odp_pktout_send(ctx->pktout, &pkt, 1) < 1) { + rc = PKT_DROP; + } else { + rc = PKT_DONE; + } + break; + + default: + rc = PKT_DROP; + break; + } + } while (PKT_CONTINUE == rc); + + /* Free context on drop or transmit */ + if ((PKT_DROP == rc) || (PKT_DONE == rc)) + free_pkt_ctx(ctx); + + + /* Check for drop */ + if (PKT_DROP == rc) + odp_packet_free(pkt); + + /* Print packet counts every once in a while */ + if (PKT_DONE == rc) { + if (odp_unlikely(pkt_cnt++ % 1000 == 0)) { + printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); + fflush(NULL); + } + } + } + + return 0; +} + +/** + * ODP ipsec example main function + */ +int +main(int argc, char *argv[]) +{ + odph_helper_options_t helper_options; + odph_odpthread_t thread_tbl[MAX_WORKERS]; + int num_workers; + int i; + int stream_count; + odp_shm_t shm; + odp_cpumask_t cpumask; + char cpumaskstr[ODP_CPUMASK_STR_SIZE]; + odp_pool_param_t params; + odp_instance_t instance; + odp_init_t init_param; + odph_odpthread_params_t thr_params; + + /* create by default scheduled queues */ + queue_create = odp_queue_create; + schedule_fn = odp_schedule_cb; + + /* check for using poll queues */ + if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) { + queue_create = polled_odp_queue_create; + schedule_fn = polled_odp_schedule_cb; + } + + /* Let helper collect its own arguments (e.g. --odph_proc) */ + argc = odph_parse_options(argc, argv); + if (odph_options(&helper_options)) { + ODPH_ERR("Error: reading ODP helper options failed.\n"); + exit(EXIT_FAILURE); + } + + /* Signal handler has to be registered before global init in case ODP + * implementation creates internal threads/processes. */ + signal(SIGINT, sig_handler); + + odp_init_param_init(&init_param); + init_param.mem_model = helper_options.mem_model; + + /* Init ODP before calling anything else */ + if (odp_init_global(&instance, &init_param, NULL)) { + ODPH_ERR("Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Init this thread */ + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + ODPH_ERR("Error: ODP local init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Reserve memory for args from shared mem */ + shm = odp_shm_reserve("shm_args", sizeof(global_data_t), + ODP_CACHE_LINE_SIZE, 0); + + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Error: shared mem reserve failed.\n"); + exit(EXIT_FAILURE); + } + + global = odp_shm_addr(shm); + + if (NULL == global) { + ODPH_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(global, 0, sizeof(global_data_t)); + global->shm = shm; + odp_atomic_init_u32(&global->exit_threads, 0); + + /* Configure scheduler */ + odp_schedule_config(NULL); + + /* Must init our databases before parsing args */ + ipsec_init_pre(); + init_fwd_db(); + init_stream_db(); + + /* Parse and store the application arguments */ + parse_args(argc, argv, &global->appl); + + /* Print both system and application information */ + print_info(NO_PATH(argv[0]), &global->appl); + + num_workers = MAX_WORKERS; + if (global->appl.cpu_count && global->appl.cpu_count < MAX_WORKERS) + num_workers = global->appl.cpu_count; + + /* Get default worker cpumask */ + num_workers = odp_cpumask_default_worker(&cpumask, num_workers); + (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr)); + + printf("num worker threads: %i\n", num_workers); + printf("first CPU: %i\n", odp_cpumask_first(&cpumask)); + printf("cpu mask: %s\n", cpumaskstr); + + /* Create a barrier to synchronize thread startup */ + odp_barrier_init(&global->sync_barrier, num_workers); + + /* Create packet buffer pool */ + odp_pool_param_init(¶ms); + params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE; + params.pkt.len = SHM_PKT_POOL_BUF_SIZE; + params.pkt.num = SHM_PKT_POOL_BUF_COUNT; + params.type = ODP_POOL_PACKET; + + global->pkt_pool = odp_pool_create("packet_pool", ¶ms); + + if (ODP_POOL_INVALID == global->pkt_pool) { + ODPH_ERR("Error: packet pool create failed.\n"); + exit(EXIT_FAILURE); + } + + /* Create context buffer pool */ + params.buf.size = SHM_CTX_POOL_BUF_SIZE; + params.buf.align = 0; + params.buf.num = SHM_CTX_POOL_BUF_COUNT; + params.type = ODP_POOL_BUFFER; + + global->ctx_pool = odp_pool_create("ctx_pool", ¶ms); + + if (ODP_POOL_INVALID == global->ctx_pool) { + ODPH_ERR("Error: context pool create failed.\n"); + exit(EXIT_FAILURE); + } + + /* Populate our IPsec cache */ + printf("Using %s mode for crypto API\n\n", + (CRYPTO_API_SYNC == global->appl.mode) ? "SYNC" : + (CRYPTO_API_ASYNC_IN_PLACE == global->appl.mode) ? + "ASYNC_IN_PLACE" : "ASYNC_NEW_BUFFER"); + ipsec_init_post(global->appl.mode); + + /* Initialize interfaces (which resolves FWD DB entries */ + for (i = 0; i < global->appl.if_count; i++) + initialize_intf(global->appl.if_names[i]); + + /* If we have test streams build them before starting workers */ + resolve_stream_db(); + stream_count = create_stream_db_inputs(); + if (stream_count < 0) { + ODPH_ERR("Error: creating input packets failed\n"); + exit(EXIT_FAILURE); + } + + /* + * Create and init worker threads + */ + memset(thread_tbl, 0, sizeof(thread_tbl)); + memset(&thr_params, 0, sizeof(thr_params)); + thr_params.start = pktio_thread; + thr_params.arg = NULL; + thr_params.thr_type = ODP_THREAD_WORKER; + thr_params.instance = instance; + odph_odpthreads_create(thread_tbl, &cpumask, &thr_params); + + /* If there are streams attempt to verify them. Otherwise, run until + * SIGINT is received. */ + if (stream_count) { + odp_bool_t done; + + do { + done = verify_stream_db_outputs(); + sleep(1); + } while (!done); + printf("All received\n"); + odp_atomic_store_u32(&global->exit_threads, 1); + } + odph_odpthreads_join(thread_tbl); + + /* Stop and close used pktio devices */ + for (i = 0; i < global->appl.if_count; i++) { + odp_pktio_t pktio = odp_pktio_lookup(global->appl.if_names[i]); + + if (pktio == ODP_PKTIO_INVALID) + continue; + + if (odp_pktio_stop(pktio) || odp_pktio_close(pktio)) { + ODPH_ERR("Error: failed to close pktio %s\n", + global->appl.if_names[i]); + exit(EXIT_FAILURE); + } + } + + free(global->appl.if_names); + free(global->appl.if_str); + + if (destroy_ipsec_cache()) + ODPH_ERR("Error: crypto session destroy failed\n"); + + if (odp_queue_destroy(global->completionq)) + ODPH_ERR("Error: queue destroy failed\n"); + if (odp_queue_destroy(global->seqnumq)) + ODPH_ERR("Error: queue destroy failed\n"); + + if (odp_pool_destroy(global->pkt_pool)) + ODPH_ERR("Error: pool destroy failed\n"); + if (odp_pool_destroy(global->ctx_pool)) + ODPH_ERR("Error: pool destroy failed\n"); + if (odp_pool_destroy(global->out_pool)) + ODPH_ERR("Error: pool destroy failed\n"); + + shm = odp_shm_lookup("shm_ipsec_cache"); + if (odp_shm_free(shm) != 0) + ODPH_ERR("Error: shm free shm_ipsec_cache failed\n"); + shm = odp_shm_lookup("shm_fwd_db"); + if (odp_shm_free(shm) != 0) + ODPH_ERR("Error: shm free shm_fwd_db failed\n"); + shm = odp_shm_lookup("shm_sa_db"); + if (odp_shm_free(shm) != 0) + ODPH_ERR("Error: shm free shm_sa_db failed\n"); + shm = odp_shm_lookup("shm_tun_db"); + if (odp_shm_free(shm) != 0) + ODPH_ERR("Error: shm free shm_tun_db failed\n"); + shm = odp_shm_lookup("shm_sp_db"); + if (odp_shm_free(shm) != 0) + ODPH_ERR("Error: shm free shm_sp_db failed\n"); + shm = odp_shm_lookup("stream_db"); + if (odp_shm_free(shm) != 0) + ODPH_ERR("Error: shm free stream_db failed\n"); + if (odp_shm_free(global->shm)) { + ODPH_ERR("Error: shm free global data failed\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_local()) { + ODPH_ERR("Error: term local failed\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_global(instance)) { + ODPH_ERR("Error: term global failed\n"); + exit(EXIT_FAILURE); + } + + printf("Exit\n\n"); + + return 0; +} + +/** + * Parse and store the command line arguments + * + * @param argc argument count + * @param argv[] argument vector + * @param appl_args Store application arguments here + */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) +{ + int opt; + int long_index; + char *token; + size_t len; + int rc = 0; + int i; + + static const struct option longopts[] = { + {"count", required_argument, NULL, 'c'}, + {"interface", required_argument, NULL, 'i'}, /* return 'i' */ + {"mode", required_argument, NULL, 'm'}, /* return 'm' */ + {"route", required_argument, NULL, 'r'}, /* return 'r' */ + {"policy", required_argument, NULL, 'p'}, /* return 'p' */ + {"ah", required_argument, NULL, 'a'}, /* return 'a' */ + {"esp", required_argument, NULL, 'e'}, /* return 'e' */ + {"tunnel", required_argument, NULL, 't'}, /* return 't' */ + {"stream", required_argument, NULL, 's'}, /* return 's' */ + {"help", no_argument, NULL, 'h'}, /* return 'h' */ + {NULL, 0, NULL, 0} + }; + + static const char *shortopts = "+c:i:m:r:p:a:e:t:s:h"; + + printf("\nParsing command line options\n"); + + appl_args->cpu_count = 1; /* use one worker by default */ + appl_args->mode = 0; /* turn off async crypto API by default */ + + while (!rc) { + opt = getopt_long(argc, argv, shortopts, longopts, &long_index); + + if (-1 == opt) + break; /* No more options */ + + switch (opt) { + case 'c': + appl_args->cpu_count = atoi(optarg); + break; + /* parse packet-io interface names */ + case 'i': + len = strlen(optarg); + if (0 == len) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + len += 1; /* add room for '\0' */ + + appl_args->if_str = malloc(len); + if (appl_args->if_str == NULL) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* count the number of tokens separated by ',' */ + strcpy(appl_args->if_str, optarg); + for (token = strtok(appl_args->if_str, ","), i = 0; + token != NULL; + token = strtok(NULL, ","), i++) + ; + + appl_args->if_count = i; + + if (0 == appl_args->if_count) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* allocate storage for the if names */ + appl_args->if_names = + calloc(appl_args->if_count, sizeof(char *)); + + /* store the if names (reset names string) */ + strcpy(appl_args->if_str, optarg); + for (token = strtok(appl_args->if_str, ","), i = 0; + token != NULL; token = strtok(NULL, ","), i++) { + appl_args->if_names[i] = token; + } + break; + + case 'm': + appl_args->mode = atoi(optarg); + break; + + case 'r': + rc = create_fwd_db_entry(optarg, appl_args->if_names, + appl_args->if_count); + break; + + case 'p': + rc = create_sp_db_entry(optarg, TRUE); + break; + + case 'a': + rc = create_sa_db_entry(optarg, FALSE); + break; + + case 'e': + rc = create_sa_db_entry(optarg, TRUE); + break; + + case 't': + rc = create_tun_db_entry(optarg); + break; + + case 's': + rc = create_stream_db_entry(optarg); + break; + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + + default: + break; + } + } + + if (rc) { + printf("ERROR: failed parsing -%c option\n", opt); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (0 == appl_args->if_count) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + optind = 1; /* reset 'extern optind' from the getopt lib */ +} + +/** + * Print system and application info + */ +static void print_info(char *progname, appl_args_t *appl_args) +{ + int i; + + odp_sys_info_print(); + + printf("Running ODP appl: \"%s\"\n" + "-----------------\n" + "IF-count: %i\n" + "Using IFs: ", + progname, appl_args->if_count); + for (i = 0; i < appl_args->if_count; ++i) + printf(" %s", appl_args->if_names[i]); + + printf("\n"); + + dump_fwd_db(); + dump_sp_db(); + dump_sa_db(); + dump_tun_db(); + printf("\n\n"); + fflush(NULL); +} + +/** + * Prinf usage information + */ +static void usage(char *progname) +{ + printf("\n" + "Usage: %s OPTIONS\n" + " E.g. %s -i eth1,eth2,eth3 -m 0\n" + "\n" + "OpenDataPlane example application.\n" + "\n" + "Mandatory OPTIONS:\n" + " -i, --interface Eth interfaces (comma-separated, no spaces)\n" + " -m, --mode 0: SYNC\n" + " 1: ASYNC_IN_PLACE\n" + " 2: ASYNC_NEW_BUFFER\n" + " Default: 0: SYNC api mode\n" + "\n" + "Routing / IPSec OPTIONS:\n" + " -r, --route SubNet:Intf:NextHopMAC\n" + " -p, --policy SrcSubNet:DstSubNet:(in|out):(ah|esp|both)\n" + " -e, --esp SrcIP:DstIP:(3des|null):SPI:Key192\n" + " -a, --ah SrcIP:DstIP:(sha256|md5|null):SPI:Key(256|128)\n" + "\n" + " Where: NextHopMAC is raw hex/dot notation, i.e. 03.BA.44.9A.CE.02\n" + " IP is decimal/dot notation, i.e. 192.168.1.1\n" + " SubNet is decimal/dot/slash notation, i.e 192.168.0.0/16\n" + " SPI is raw hex, 32 bits\n" + " KeyXXX is raw hex, XXX bits long\n" + "\n" + " Examples:\n" + " -r 192.168.222.0/24:p8p1:08.00.27.F5.8B.DB\n" + " -p 192.168.111.0/24:192.168.222.0/24:out:esp\n" + " -e 192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n" + " -a 192.168.111.2:192.168.222.2:md5:201:a731649644c5dee92cbd9c2e7e188ee6\n" + "\n" + "Optional OPTIONS\n" + " -c, --count CPU count, 0=all available, default=1\n" + " -s, --stream SrcIP:DstIP:InIntf:OutIntf:Count:Length\n" + " -h, --help Display help and exit.\n" + " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n" + " to enable use of poll queues instead of scheduled (default)\n" + " ODP_IPSEC_STREAM_VERIFY_MDEQ\n" + " to enable use of multiple dequeue for queue draining during\n" + " stream verification instead of single dequeue (default)\n" + "\n", NO_PATH(progname), NO_PATH(progname) + ); +} diff --git a/example/ipsec_crypto/odp_ipsec_cache.c b/example/ipsec_crypto/odp_ipsec_cache.c new file mode 100644 index 000000000..044538c59 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_cache.c @@ -0,0 +1,243 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#include + +#include + +/** Global pointer to ipsec_cache db */ +ipsec_cache_t *ipsec_cache; + +void init_ipsec_cache(void) +{ + odp_shm_t shm; + int i; + + shm = odp_shm_reserve("shm_ipsec_cache", + sizeof(ipsec_cache_t), + ODP_CACHE_LINE_SIZE, + 0); + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + + ipsec_cache = odp_shm_addr(shm); + + if (ipsec_cache == NULL) { + ODPH_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(ipsec_cache, 0, sizeof(*ipsec_cache)); + + for (i = 0; i < MAX_DB; i++) + ipsec_cache->array[i].state.session = + ODP_CRYPTO_SESSION_INVALID; +} + +int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa, + sa_db_entry_t *auth_sa, + tun_db_entry_t *tun, + crypto_api_mode_e api_mode, + odp_bool_t in, + odp_queue_t completionq, + odp_pool_t out_pool) +{ + odp_crypto_session_param_t params; + ipsec_cache_entry_t *entry; + odp_crypto_ses_create_err_t ses_create_rc; + odp_crypto_session_t session; + sa_mode_t mode = IPSEC_SA_MODE_TRANSPORT; + + /* Verify we have a good entry */ + entry = &ipsec_cache->array[ipsec_cache->index]; + if (MAX_DB <= ipsec_cache->index) + return -1; + + /* Verify SA mode match in case of cipher&auth */ + if (cipher_sa && auth_sa && + (cipher_sa->mode != auth_sa->mode)) + return -1; + + odp_crypto_session_param_init(¶ms); + + /* Setup parameters and call crypto library to create session */ + params.op = (in) ? ODP_CRYPTO_OP_DECODE : ODP_CRYPTO_OP_ENCODE; + params.auth_cipher_text = TRUE; + if (CRYPTO_API_SYNC == api_mode) { + params.op_mode = ODP_CRYPTO_SYNC; + params.compl_queue = ODP_QUEUE_INVALID; + params.output_pool = ODP_POOL_INVALID; + entry->async = FALSE; + } else { + params.op_mode = ODP_CRYPTO_ASYNC; + params.compl_queue = completionq; + params.output_pool = out_pool; + entry->async = TRUE; + } + + if (CRYPTO_API_ASYNC_NEW_BUFFER == api_mode) + entry->in_place = FALSE; + else + entry->in_place = TRUE; + + + /* Cipher */ + if (cipher_sa) { + params.cipher_alg = cipher_sa->alg.u.cipher; + params.cipher_key.data = cipher_sa->key.data; + params.cipher_key.length = cipher_sa->key.length; + params.cipher_iv.data = entry->state.iv; + params.cipher_iv.length = cipher_sa->iv_len; + mode = cipher_sa->mode; + } else { + params.cipher_alg = ODP_CIPHER_ALG_NULL; + params.cipher_iv.data = NULL; + params.cipher_iv.length = 0; + } + + /* Auth */ + if (auth_sa) { + params.auth_alg = auth_sa->alg.u.auth; + params.auth_key.data = auth_sa->key.data; + params.auth_key.length = auth_sa->key.length; + params.auth_digest_len = auth_sa->icv_len; + mode = auth_sa->mode; + } else { + params.auth_alg = ODP_AUTH_ALG_NULL; + } + + /* Generate an IV */ + if (params.cipher_iv.length) { + int32_t size = params.cipher_iv.length; + + int32_t ret = odp_random_data(params.cipher_iv.data, size, 1); + if (ret != size) + return -1; + } + + /* Synchronous session create for now */ + if (odp_crypto_session_create(¶ms, &session, &ses_create_rc)) + return -1; + if (ODP_CRYPTO_SES_CREATE_ERR_NONE != ses_create_rc) + return -1; + + /* Copy remainder */ + if (cipher_sa) { + entry->src_ip = cipher_sa->src_ip; + entry->dst_ip = cipher_sa->dst_ip; + entry->esp.alg = cipher_sa->alg.u.cipher; + entry->esp.spi = cipher_sa->spi; + entry->esp.block_len = cipher_sa->block_len; + entry->esp.iv_len = cipher_sa->iv_len; + memcpy(&entry->esp.key, &cipher_sa->key, sizeof(ipsec_key_t)); + } + if (auth_sa) { + entry->src_ip = auth_sa->src_ip; + entry->dst_ip = auth_sa->dst_ip; + entry->ah.alg = auth_sa->alg.u.auth; + entry->ah.spi = auth_sa->spi; + entry->ah.icv_len = auth_sa->icv_len; + memcpy(&entry->ah.key, &auth_sa->key, sizeof(ipsec_key_t)); + } + + if (tun) { + entry->tun_src_ip = tun->tun_src_ip; + entry->tun_dst_ip = tun->tun_dst_ip; + mode = IPSEC_SA_MODE_TUNNEL; + + int ret; + + if (!in) { + /* init tun hdr id */ + ret = odp_random_data((uint8_t *) + &entry->state.tun_hdr_id, + sizeof(entry->state.tun_hdr_id), + 1); + if (ret != sizeof(entry->state.tun_hdr_id)) + return -1; + } + } + entry->mode = mode; + + /* Initialize state */ + entry->state.esp_seq = 0; + entry->state.ah_seq = 0; + entry->state.session = session; + + /* Add entry to the appropriate list */ + ipsec_cache->index++; + if (in) { + entry->next = ipsec_cache->in_list; + ipsec_cache->in_list = entry; + } else { + entry->next = ipsec_cache->out_list; + ipsec_cache->out_list = entry; + } + + return 0; +} + +ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip, + uint32_t dst_ip, + odph_ahhdr_t *ah, + odph_esphdr_t *esp) +{ + ipsec_cache_entry_t *entry = ipsec_cache->in_list; + + /* Look for a hit */ + for (; NULL != entry; entry = entry->next) { + if ((entry->src_ip != src_ip) || (entry->dst_ip != dst_ip)) + if ((entry->tun_src_ip != src_ip) || + (entry->tun_dst_ip != dst_ip)) + continue; + if (ah && + ((!entry->ah.alg) || + (entry->ah.spi != odp_be_to_cpu_32(ah->spi)))) + continue; + if (esp && + ((!entry->esp.alg) || + (entry->esp.spi != odp_be_to_cpu_32(esp->spi)))) + continue; + break; + } + + return entry; +} + +ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip, + uint32_t dst_ip, + uint8_t proto ODP_UNUSED) +{ + ipsec_cache_entry_t *entry = ipsec_cache->out_list; + + /* Look for a hit */ + for (; NULL != entry; entry = entry->next) { + if ((entry->src_ip == src_ip) && (entry->dst_ip == dst_ip)) + break; + } + return entry; +} + +int destroy_ipsec_cache(void) +{ + ipsec_cache_entry_t *entry; + int i; + int ret = 0; + + for (i = 0; i < MAX_DB; i++) { + entry = &ipsec_cache->array[i]; + if (entry->state.session != ODP_CRYPTO_SESSION_INVALID) + ret += odp_crypto_session_destroy(entry->state.session); + } + + return ret; +} diff --git a/example/ipsec_crypto/odp_ipsec_cache.h b/example/ipsec_crypto/odp_ipsec_cache.h new file mode 100644 index 000000000..1523778ff --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_cache.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_IPSEC_CACHE_H_ +#define ODP_IPSEC_CACHE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +/** + * Mode specified on command line indicating how to exercise API + */ +typedef enum { + CRYPTO_API_SYNC, /**< Synchronous mode */ + CRYPTO_API_ASYNC_IN_PLACE, /**< Asynchronous in place */ + CRYPTO_API_ASYNC_NEW_BUFFER /**< Asynchronous new buffer */ +} crypto_api_mode_e; + +/** + * IPsec cache data base entry + */ +typedef struct ipsec_cache_entry_s { + struct ipsec_cache_entry_s *next; /**< Next entry on list */ + odp_bool_t in_place; /**< Crypto API mode */ + odp_bool_t async; /**< ASYNC or SYNC mode */ + uint32_t src_ip; /**< Source v4 address */ + uint32_t dst_ip; /**< Destination v4 address */ + sa_mode_t mode; /**< SA mode - transport/tun */ + uint32_t tun_src_ip; /**< Tunnel src IPv4 addr */ + uint32_t tun_dst_ip; /**< Tunnel dst IPv4 addr */ + struct { + odp_cipher_alg_t alg; /**< Cipher algorithm */ + uint32_t spi; /**< Cipher SPI */ + uint32_t block_len; /**< Cipher block length */ + uint32_t iv_len; /**< Cipher IV length */ + ipsec_key_t key; /**< Cipher key */ + } esp; + struct { + odp_auth_alg_t alg; /**< Auth algorithm */ + uint32_t spi; /**< Auth SPI */ + uint32_t icv_len; /**< Auth ICV length */ + ipsec_key_t key; /**< Auth key */ + } ah; + + /* Per SA state */ + struct { + odp_crypto_session_t session; /**< Crypto session handle */ + uint32_t esp_seq; /**< ESP TX sequence number */ + uint32_t ah_seq; /**< AH TX sequence number */ + uint8_t iv[MAX_IV_LEN]; /**< ESP IV storage */ + odp_u16be_t tun_hdr_id; /**< Tunnel header IP ID */ + } state; +} ipsec_cache_entry_t; + +/** + * IPsec cache data base global structure + */ +typedef struct ipsec_cache_s { + uint32_t index; /**< Index of next available entry */ + ipsec_cache_entry_t *in_list; /**< List of active input entries */ + ipsec_cache_entry_t *out_list; /**< List of active output entries */ + ipsec_cache_entry_t array[MAX_DB]; /**< Entry storage */ +} ipsec_cache_t; + +/** Global pointer to ipsec_cache db */ +extern ipsec_cache_t *ipsec_cache; + +/** Initialize IPsec cache */ +void init_ipsec_cache(void); + +/** + * Create an entry in the IPsec cache + * + * @param cipher_sa Cipher SA DB entry pointer + * @param auth_sa Auth SA DB entry pointer + * @param tun Tunnel DB entry pointer + * @param api_mode Crypto API mode for testing + * @param in Direction (input versus output) + * @param completionq Completion queue + * @param out_pool Output buffer pool + * + * @return 0 if successful else -1 + */ +int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa, + sa_db_entry_t *auth_sa, + tun_db_entry_t *tun, + crypto_api_mode_e api_mode, + odp_bool_t in, + odp_queue_t completionq, + odp_pool_t out_pool); + +/** + * Find a matching IPsec cache entry for input packet + * + * @param src_ip Source IPv4 address + * @param dst_ip Destination IPv4 address + * @param ah Pointer to AH header in packet else NULL + * @param esp Pointer to ESP header in packet else NULL + * + * @return pointer to IPsec cache entry else NULL + */ +ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip, + uint32_t dst_ip, + odph_ahhdr_t *ah, + odph_esphdr_t *esp); + +/** + * Find a matching IPsec cache entry for output packet + * + * @param src_ip Source IPv4 address + * @param dst_ip Destination IPv4 address + * @param proto IPv4 protocol (currently all protocols match) + * + * @return pointer to IPsec cache entry else NULL + */ +ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip, + uint32_t dst_ip, + uint8_t proto); + +int destroy_ipsec_cache(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh new file mode 100755 index 000000000..18045c7e9 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Test input AH +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +./odp_ipsec_crypto -i loop1,loop2 \ +-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ +-p 192.168.222.0/24:192.168.111.0/24:in:ah \ +-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ +-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh new file mode 100755 index 000000000..8ddfd203d --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Test output AH +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +./odp_ipsec_crypto -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:ah \ +-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh new file mode 100755 index 000000000..4ad08a784 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# +# Test AH and ESP input +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +./odp_ipsec_crypto -i loop1,loop2 \ +-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ +-p 192.168.222.0/24:192.168.111.0/24:in:both \ +-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ +-e 192.168.222.2:192.168.111.2:\ +3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ +-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh new file mode 100755 index 000000000..a9e3ac8af --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# +# Test AH and ESP output +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +./odp_ipsec_crypto -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:both \ +-e 192.168.111.2:192.168.222.2:\ +3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh new file mode 100755 index 000000000..62f73cf7d --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Test input ESP +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +./odp_ipsec_crypto -i loop1,loop2 \ +-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ +-p 192.168.222.0/24:192.168.111.0/24:in:esp \ +-e 192.168.222.2:192.168.111.2:\ +3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ +-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh new file mode 100755 index 000000000..cd9db1e2a --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Test output ESP +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line + +if [ -z "$IPSEC_EXAMPLE_PATH" ]; then +IPSEC_EXAMPLE_PATH=. +fi + +${IPSEC_EXAMPLE_PATH}/odp_ipsec_crypto -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:esp \ +-e 192.168.111.2:192.168.222.2:\ +3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_live.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_live.sh new file mode 100755 index 000000000..e893674bc --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_live.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Live router test +# - 2 interfaces interfaces +# - Specify API mode on command line +sudo ./odp_ipsec_crypto -i p7p1,p8p1 \ +-r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ +-r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:both \ +-e 192.168.111.2:192.168.222.2:\ +3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ +-p 192.168.222.0/24:192.168.111.0/24:in:both \ +-e 192.168.222.2:192.168.111.2:\ +3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ +-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ +-c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_router.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_router.sh new file mode 100755 index 000000000..920f28e0d --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_router.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# +# Live router test +# - 2 interfaces interfaces +# - Specify API mode on command line +sudo ./odp_ipsec_crypto -i p7p1,p8p1 \ +-r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ +-r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ +-c 1 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh new file mode 100755 index 000000000..3613fe5fd --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# +# Simple router test +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line + +if [ -z "$IPSEC_EXAMPLE_PATH" ]; then +IPSEC_EXAMPLE_PATH=. +fi + +${IPSEC_EXAMPLE_PATH}/odp_ipsec_crypto -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_crypto/odp_ipsec_fwd_db.c b/example/ipsec_crypto/odp_ipsec_fwd_db.c new file mode 100644 index 000000000..ca0abf6c1 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_fwd_db.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#include +#include + +#include + +/** Global pointer to fwd db */ +fwd_db_t *fwd_db; + +void init_fwd_db(void) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("shm_fwd_db", + sizeof(fwd_db_t), + ODP_CACHE_LINE_SIZE, + 0); + + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Error: shared mem reserve failed.\n"); + exit(EXIT_FAILURE); + } + + fwd_db = odp_shm_addr(shm); + + if (fwd_db == NULL) { + ODPH_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(fwd_db, 0, sizeof(*fwd_db)); +} + +int create_fwd_db_entry(char *input, char **if_names, int if_count) +{ + int pos = 0, i, match = 0; + char *local; + char *str; + char *save; + char *token; + fwd_db_entry_t *entry = &fwd_db->array[fwd_db->index]; + + /* Verify we haven't run out of space */ + if (MAX_DB <= fwd_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->subnet.addr, + &entry->subnet.mask); + break; + case 1: + strncpy(entry->oif, token, OIF_LEN - 1); + entry->oif[OIF_LEN - 1] = 0; + for (i = 0; i < if_count; i++) { + if (!strcmp(if_names[i], entry->oif)) { + match = 1; + break; + } + } + if (!match) { + printf("ERROR: interface name not correct for route\n"); + free(local); + return -1; + } + break; + case 2: + parse_mac_string(token, entry->dst_mac); + 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 (3 != pos) { + printf("ERROR: \"%s\" contains %d tokens, expected 3\n", + input, + pos); + free(local); + return -1; + } + + /* Add route to the list */ + fwd_db->index++; + entry->next = fwd_db->list; + fwd_db->list = entry; + + free(local); + return 0; +} + +void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout, + uint8_t *mac) +{ + fwd_db_entry_t *entry; + + /* Walk the list and attempt to set output queue and MAC */ + for (entry = fwd_db->list; NULL != entry; entry = entry->next) { + if (strcmp(intf, entry->oif)) + continue; + + entry->pktio = pktio; + entry->pktout = pktout; + memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN); + } +} + +void dump_fwd_db_entry(fwd_db_entry_t *entry) +{ + char subnet_str[MAX_STRING]; + char mac_str[MAX_STRING]; + + printf(" %s %s %s\n", + ipv4_subnet_str(subnet_str, &entry->subnet), + entry->oif, + mac_addr_str(mac_str, entry->dst_mac)); +} + +void dump_fwd_db(void) +{ + fwd_db_entry_t *entry; + + printf("\n" + "Routing table\n" + "-------------\n"); + + for (entry = fwd_db->list; NULL != entry; entry = entry->next) + dump_fwd_db_entry(entry); +} + +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip) +{ + fwd_db_entry_t *entry; + + for (entry = fwd_db->list; NULL != entry; entry = entry->next) + if (entry->subnet.addr == (dst_ip & entry->subnet.mask)) + break; + return entry; +} diff --git a/example/ipsec_crypto/odp_ipsec_fwd_db.h b/example/ipsec_crypto/odp_ipsec_fwd_db.h new file mode 100644 index 000000000..278259729 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_fwd_db.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_IPSEC_FWD_DB_H_ +#define ODP_IPSEC_FWD_DB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define OIF_LEN 32 + +/** + * Forwarding data base entry + */ +typedef struct fwd_db_entry_s { + struct fwd_db_entry_s *next; /**< Next entry on list */ + char oif[OIF_LEN]; /**< Output interface name */ + odp_pktio_t pktio; /**< Output PktI/O interface */ + odp_pktout_queue_t pktout; /**< Output transmit queue */ + uint8_t src_mac[ODPH_ETHADDR_LEN]; /**< Output source MAC */ + uint8_t dst_mac[ODPH_ETHADDR_LEN]; /**< Output destination MAC */ + ip_addr_range_t subnet; /**< Subnet for this router */ +} fwd_db_entry_t; + +/** + * Forwarding data base global structure + */ +typedef struct fwd_db_s { + uint32_t index; /**< Next available entry */ + fwd_db_entry_t *list; /**< List of active routes */ + fwd_db_entry_t array[MAX_DB]; /**< Entry storage */ +} fwd_db_t; + +/** Global pointer to fwd db */ +extern fwd_db_t *fwd_db; + +/** Initialize FWD DB */ +void init_fwd_db(void); + +/** + * Create a forwarding database entry + * + * String is of the format "SubNet:Intf:NextHopMAC" + * + * @param input Pointer to string describing route + * + * @param if_names Array of Name of the interfaces available + * + * @param if_count number of interfaces in if_names array + * + * @return 0 if successful else -1 + */ +int create_fwd_db_entry(char *input, char **if_names, int if_count); + +/** + * Scan FWD DB entries and resolve output queue and source MAC address + * + * @param intf Interface name string + * @param pktio Output packet interface + * @param outq Output queue for packet transmit + * @param mac MAC address of this interface + */ +void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout, + uint8_t *mac); + +/** + * Display one fowarding database entry + * + * @param entry Pointer to entry to display + */ +void dump_fwd_db_entry(fwd_db_entry_t *entry); + +/** + * Display the forwarding database + */ +void dump_fwd_db(void); + +/** + * Find a matching forwarding database entry + * + * @param dst_ip Destination IPv4 address + * + * @return pointer to forwarding DB entry else NULL + */ +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/ipsec_crypto/odp_ipsec_misc.h b/example/ipsec_crypto/odp_ipsec_misc.h new file mode 100644 index 000000000..71d8f63c4 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_misc.h @@ -0,0 +1,343 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_IPSEC_MISC_H_ +#define ODP_IPSEC_MISC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define MAX_DB 32 /**< maximum number of data base entries */ +#define MAX_LOOPBACK 10 /**< maximum number of loop back interfaces */ +#define MAX_STRING 32 /**< maximum string length */ +#define MAX_IV_LEN 32 /**< Maximum IV length in bytes */ + +#define KEY_BITS_3DES 192 /**< 3DES cipher key length in bits */ +#define KEY_BITS_MD5_96 128 /**< MD5_96 auth key length in bits */ +#define KEY_BITS_SHA256_128 256 /**< SHA256_128 auth key length in bits */ + +/**< Number of bits represnted by a string of hexadecimal characters */ +#define KEY_STR_BITS(str) (4 * strlen(str)) + +/** IPv4 helpers for data length and uint8t pointer */ +#define ipv4_data_len(ip) (odp_be_to_cpu_16(ip->tot_len) - sizeof(odph_ipv4hdr_t)) +#define ipv4_data_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1)) + +/** Helper for calculating encode length using data length and block size */ +#define ESP_ENCODE_LEN(x, b) ((((x) + (b - 1)) / b) * b) + +/** Get rid of path in filename - only for unix-type paths using '/' */ +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ + strrchr((file_name), '/') + 1 : (file_name)) + +/** + * IPsec key + */ +typedef struct { + uint8_t data[32]; /**< Key data */ + uint8_t length; /**< Key length */ +} ipsec_key_t; + +/** + * IPsec algorithm + */ +typedef struct { + odp_bool_t cipher; + union { + odp_cipher_alg_t cipher; + odp_auth_alg_t auth; + } u; +} ipsec_alg_t; + +/** + * IP address range (subnet) + */ +typedef struct ip_addr_range_s { + uint32_t addr; /**< IP address */ + uint32_t mask; /**< mask, 1 indicates bits are valid */ +} ip_addr_range_t; + +/** + * Parse text string representing a key into ODP key structure + * + * @param keystring Pointer to key string to convert + * @param key Pointer to ODP key structure to populate + * @param alg Cipher/authentication algorithm associated with the key + * + * @return 0 if successful else -1 + */ +static inline +int parse_key_string(char *keystring, + ipsec_key_t *key, + ipsec_alg_t *alg) +{ + int idx; + int key_bits_in = KEY_STR_BITS(keystring); + char temp[3]; + + key->length = 0; + + /* Algorithm is either cipher or authentication */ + if (alg->cipher) { + if ((alg->u.cipher == ODP_CIPHER_ALG_3DES_CBC) && + (KEY_BITS_3DES == key_bits_in)) + key->length = key_bits_in / 8; + + } else { + if ((alg->u.auth == ODP_AUTH_ALG_MD5_HMAC) && + (KEY_BITS_MD5_96 == key_bits_in)) + key->length = key_bits_in / 8; + else if ((alg->u.auth == ODP_AUTH_ALG_SHA256_HMAC) && + (KEY_BITS_SHA256_128 == key_bits_in)) + key->length = key_bits_in / 8; + } + + for (idx = 0; idx < key->length; idx++) { + temp[0] = *keystring++; + temp[1] = *keystring++; + temp[2] = 0; + key->data[idx] = strtol(temp, NULL, 16); + } + + return key->length ? 0 : -1; +} + +/** + * Check IPv4 address against a range/subnet + * + * @param addr IPv4 address to check + * @param range Pointer to address range to check against + * + * @return 1 if match else 0 + */ +static inline +int match_ip_range(uint32_t addr, ip_addr_range_t *range) +{ + return (range->addr == (addr & range->mask)); +} + +/** + * Generate text string representing IPv4 address + * + * @param b Pointer to buffer to store string + * @param addr IPv4 address + * + * @return Pointer to supplied buffer + */ +static inline +char *ipv4_addr_str(char *b, uint32_t addr) +{ + sprintf(b, "%03d.%03d.%03d.%03d", + 0xFF & ((addr) >> 24), + 0xFF & ((addr) >> 16), + 0xFF & ((addr) >> 8), + 0xFF & ((addr) >> 0)); + return b; +} + +/** + * Parse text string representing an IPv4 address or subnet + * + * String is of the format "XXX.XXX.XXX.XXX(/W)" where + * "XXX" is decimal value and "/W" is optional subnet length + * + * @param ipaddress Pointer to IP address/subnet string to convert + * @param addr Pointer to return IPv4 address + * @param mask Pointer (optional) to return IPv4 mask + * + * @return 0 if successful else -1 + */ +static inline +int parse_ipv4_string(char *ipaddress, uint32_t *addr, uint32_t *mask) +{ + int b[4]; + int qualifier = 32; + int converted; + + if (strchr(ipaddress, '/')) { + converted = sscanf(ipaddress, "%d.%d.%d.%d/%d", + &b[3], &b[2], &b[1], &b[0], + &qualifier); + if (5 != converted) + return -1; + } else { + converted = sscanf(ipaddress, "%d.%d.%d.%d", + &b[3], &b[2], &b[1], &b[0]); + if (4 != converted) + return -1; + } + + if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255)) + return -1; + if (!qualifier || (qualifier > 32)) + return -1; + + *addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; + if (mask) + *mask = ~(0xFFFFFFFF & ((1ULL << (32 - qualifier)) - 1)); + + return 0; +} + +/** + * Generate text string representing IPv4 range/subnet, output + * in "XXX.XXX.XXX.XXX/W" format + * + * @param b Pointer to buffer to store string + * @param range Pointer to IPv4 address range + * + * @return Pointer to supplied buffer + */ +static inline +char *ipv4_subnet_str(char *b, ip_addr_range_t *range) +{ + int idx; + int len; + + for (idx = 0; idx < 32; idx++) + if (range->mask & (1 << idx)) + break; + len = 32 - idx; + + sprintf(b, "%03d.%03d.%03d.%03d/%d", + 0xFF & ((range->addr) >> 24), + 0xFF & ((range->addr) >> 16), + 0xFF & ((range->addr) >> 8), + 0xFF & ((range->addr) >> 0), + len); + return b; +} + +/** + * Generate text string representing MAC address + * + * @param b Pointer to buffer to store string + * @param mac Pointer to MAC address + * + * @return Pointer to supplied buffer + */ +static inline +char *mac_addr_str(char *b, uint8_t *mac) +{ + sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return b; +} + +/** + * Parse text string representing a MAC address into byte araray + * + * String is of the format "XX.XX.XX.XX.XX.XX" where XX is hexadecimal + * + * @param macaddress Pointer to MAC address string to convert + * @param mac Pointer to MAC address byte array to populate + * + * @return 0 if successful else -1 + */ +static inline +int parse_mac_string(char *macaddress, uint8_t *mac) +{ + int macwords[ODPH_ETHADDR_LEN]; + int converted; + + converted = sscanf(macaddress, + "%x.%x.%x.%x.%x.%x", + &macwords[0], &macwords[1], &macwords[2], + &macwords[3], &macwords[4], &macwords[5]); + if (6 != converted) + return -1; + + mac[0] = macwords[0]; + mac[1] = macwords[1]; + mac[2] = macwords[2]; + mac[3] = macwords[3]; + mac[4] = macwords[4]; + mac[5] = macwords[5]; + + return 0; +} + +/** + * Locate IPsec headers (AH and/or ESP) in packet + * + * @param ip Pointer to packets IPv4 header + * @param ah_p Pointer to location to return AH header pointer + * @param esp_p Pointer to location to return ESP header pointer + * + * @return length of IPsec headers found + */ +static inline +int locate_ipsec_headers(odph_ipv4hdr_t *ip, + odph_ahhdr_t **ah_p, + odph_esphdr_t **esp_p) +{ + uint8_t *in = ipv4_data_p(ip); + odph_ahhdr_t *ah = NULL; + odph_esphdr_t *esp = NULL; + + if (ODPH_IPPROTO_AH == ip->proto) { + ah = (odph_ahhdr_t *)in; + in += ((ah)->ah_len + 2) * 4; + if (ODPH_IPPROTO_ESP == ah->next_header) { + esp = (odph_esphdr_t *)in; + in += sizeof(odph_esphdr_t); + } + } else if (ODPH_IPPROTO_ESP == ip->proto) { + esp = (odph_esphdr_t *)in; + in += sizeof(odph_esphdr_t); + } + + *ah_p = ah; + *esp_p = esp; + return in - (ipv4_data_p(ip)); +} + +/** + * Adjust IPv4 length + * + * @param ip Pointer to IPv4 header + * @param adj Signed adjustment value + */ +static inline +void ipv4_adjust_len(odph_ipv4hdr_t *ip, int adj) +{ + ip->tot_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->tot_len) + adj); +} + +/** + * Verify crypto operation completed successfully + * + * @param status Pointer to cryto completion structure + * + * @return TRUE if all OK else FALSE + */ +static inline +odp_bool_t is_crypto_op_status_ok(odp_crypto_op_status_t *status) +{ + if (status->alg_err != ODP_CRYPTO_ALG_ERR_NONE) + return FALSE; + if (status->hw_err != ODP_CRYPTO_HW_ERR_NONE) + return FALSE; + return TRUE; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/ipsec_crypto/odp_ipsec_sa_db.c b/example/ipsec_crypto/odp_ipsec_sa_db.c new file mode 100644 index 000000000..9a7c593b3 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_sa_db.c @@ -0,0 +1,328 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#include +#include + +#include + +/** Global pointer to sa db */ +static sa_db_t *sa_db; + +/** Global pointer to tun db */ +static tun_db_t *tun_db; + +void init_sa_db(void) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("shm_sa_db", + sizeof(sa_db_t), + ODP_CACHE_LINE_SIZE, + 0); + + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Error: shared mem reserve failed.\n"); + exit(EXIT_FAILURE); + } + + sa_db = odp_shm_addr(shm); + + if (sa_db == NULL) { + ODPH_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(sa_db, 0, sizeof(*sa_db)); +} + +void init_tun_db(void) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("shm_tun_db", + sizeof(tun_db_t), + ODP_CACHE_LINE_SIZE, + 0); + + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Error: shared mem reserve failed.\n"); + exit(EXIT_FAILURE); + } + + tun_db = odp_shm_addr(shm); + + if (!tun_db) { + ODPH_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(tun_db, 0, sizeof(*tun_db)); +} + +int create_sa_db_entry(char *input, odp_bool_t cipher) +{ + int pos = 0; + char *local; + char *str; + char *save; + char *token; + sa_db_entry_t *entry = &sa_db->array[sa_db->index]; + + /* Verify we have a good entry */ + if (MAX_DB <= sa_db->index) + return -1; + + /* Make a local copy */ + local = malloc(strlen(input) + 1); + if (NULL == local) + return -1; + strcpy(local, input); + + /* Set cipher versus auth */ + entry->alg.cipher = cipher; + + /* 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: + if (cipher) { + if (0 == strcmp(token, "3des")) { + entry->alg.u.cipher = + ODP_CIPHER_ALG_3DES_CBC; + entry->block_len = 8; + entry->iv_len = 8; + } else { + entry->alg.u.cipher = + ODP_CIPHER_ALG_NULL; + } + } else { + if (0 == strcmp(token, "md5")) { + entry->alg.u.auth = + ODP_AUTH_ALG_MD5_HMAC; + entry->icv_len = 12; + } else if (!strcmp(token, "sha256")) { + entry->alg.u.auth = + ODP_AUTH_ALG_SHA256_HMAC; + entry->icv_len = 16; + } else { + entry->alg.u.auth = ODP_AUTH_ALG_NULL; + } + } + break; + case 3: + entry->spi = strtol(token, NULL, 16); + break; + case 4: + parse_key_string(token, + &entry->key, + &entry->alg); + 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 (5 != pos) { + printf("ERROR: \"%s\" contains %d tokens, expected 5\n", + input, + pos); + free(local); + return -1; + } + + /* Add route to the list */ + sa_db->index++; + entry->next = sa_db->list; + sa_db->list = entry; + + free(local); + return 0; +} + +int create_tun_db_entry(char *input) +{ + int pos = 0; + char *local; + char *str; + char *save; + char *token; + tun_db_entry_t *entry = &tun_db->array[tun_db->index]; + + /* Verify we have a good entry */ + if (MAX_DB <= tun_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: + parse_ipv4_string(token, &entry->tun_src_ip, NULL); + break; + case 3: + parse_ipv4_string(token, &entry->tun_dst_ip, NULL); + break; + default: + printf("ERROR: extra token \"%s\" at position %d\n", + token, pos); + break; + } + pos++; + } + + /* Verify we parsed exactly the number of tokens we expected */ + if (4 != pos) { + printf("ERROR: \"%s\" contains %d tokens, expected 4\n", + input, + pos); + free(local); + return -1; + } + + /* Add route to the list */ + tun_db->index++; + entry->next = tun_db->list; + tun_db->list = entry; + + free(local); + return 0; +} + +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src, + uint32_t ip_dst) +{ + tun_db_entry_t *entry = NULL; + + /* Scan all entries and return first match */ + for (entry = tun_db->list; NULL != entry; entry = entry->next) { + if (entry->src_ip != ip_src) + continue; + if (entry->dst_ip != ip_dst) + continue; + break; + } + return entry; +} + +void dump_sa_db(void) +{ + sa_db_entry_t *entry; + + printf("\n" + "Security association table\n" + "--------------------------\n"); + + for (entry = sa_db->list; NULL != entry; entry = entry->next) { + uint32_t idx; + char src_ip_str[MAX_STRING]; + char dst_ip_str[MAX_STRING]; + uint8_t *p = entry->key.data; + + + printf(" %s %s %s %X %d ", + entry->alg.cipher ? "esp" : "ah ", + ipv4_addr_str(src_ip_str, entry->src_ip), + ipv4_addr_str(dst_ip_str, entry->dst_ip), + entry->spi, + entry->alg.cipher ? + (int)entry->alg.u.cipher : + (int)entry->alg.u.auth); + + /* Brute force key display */ + for (idx = 0; idx < entry->key.length; idx++) + printf("%02X", *p++); + + printf("\n"); + } +} + +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src, + ip_addr_range_t *dst, + odp_bool_t cipher) +{ + sa_db_entry_t *entry = NULL; + + /* Scan all entries and return first match */ + for (entry = sa_db->list; NULL != entry; entry = entry->next) { + if (cipher != entry->alg.cipher) + continue; + if (!match_ip_range(entry->src_ip, src)) + continue; + if (!match_ip_range(entry->dst_ip, dst)) + continue; + break; + } + return entry; +} + +void dump_tun_db(void) +{ + tun_db_entry_t *entry; + + printf("\n" + "Tunnel table\n" + "--------------------------\n"); + + for (entry = tun_db->list; NULL != entry; entry = entry->next) { + char src_ip_str[MAX_STRING]; + char dst_ip_str[MAX_STRING]; + char tun_src_ip_str[MAX_STRING]; + char tun_dst_ip_str[MAX_STRING]; + + printf(" %s:%s %s:%s ", + ipv4_addr_str(src_ip_str, entry->src_ip), + ipv4_addr_str(dst_ip_str, entry->dst_ip), + ipv4_addr_str(tun_src_ip_str, entry->tun_src_ip), + ipv4_addr_str(tun_dst_ip_str, entry->tun_dst_ip) + ); + + printf("\n"); + } +} diff --git a/example/ipsec_crypto/odp_ipsec_sa_db.h b/example/ipsec_crypto/odp_ipsec_sa_db.h new file mode 100644 index 000000000..729d98d56 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_sa_db.h @@ -0,0 +1,131 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_IPSEC_SA_DB_H_ +#define ODP_IPSEC_SA_DB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef enum sa_mode_s { + IPSEC_SA_MODE_TRANSPORT, + IPSEC_SA_MODE_TUNNEL +} sa_mode_t; +/** + * Security Association (SA) data base entry + */ +typedef struct sa_db_entry_s { + struct sa_db_entry_s *next; /**< Next entry on list */ + uint32_t src_ip; /**< Source IPv4 address */ + uint32_t dst_ip; /**< Desitnation IPv4 address */ + uint32_t spi; /**< Security Parameter Index */ + ipsec_alg_t alg; /**< Cipher/auth algorithm */ + ipsec_key_t key; /**< Cipher/auth key */ + uint32_t block_len; /**< Cipher block length */ + uint32_t iv_len; /**< Initialization Vector length */ + uint32_t icv_len; /**< Integrity Check Value length */ + sa_mode_t mode; /**< SA mode - transport/tun */ +} sa_db_entry_t; + +/** + * Security Association (SA) data base global structure + */ +typedef struct sa_db_s { + uint32_t index; /**< Index of next available entry */ + sa_db_entry_t *list; /**< List of active entries */ + sa_db_entry_t array[MAX_DB]; /**< Entry storage */ +} sa_db_t; + +/** Initialize SA database global control structure */ +void init_sa_db(void); + +/** + * Create an SA DB entry + * + * String is of the format "SrcIP:DstIP:Alg:SPI:Key" + * + * @param input Pointer to string describing SA + * @param cipher TRUE if cipher else FALSE for auth + * + * @return 0 if successful else -1 + */ +int create_sa_db_entry(char *input, odp_bool_t cipher); +/** + * Display the SA DB + */ +void dump_sa_db(void); + +/** + * Find a matching SA DB entry + * + * @param src Pointer to source subnet/range + * @param dst Pointer to destination subnet/range + * @param cipher TRUE if cipher else FALSE for auth + * + * @return pointer to SA DB entry else NULL + */ +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src, + ip_addr_range_t *dst, + odp_bool_t cipher); + +/** + * Tunnel entry + */ +typedef struct tun_db_entry_s { + struct tun_db_entry_s *next; + uint32_t src_ip; /**< Inner Source IPv4 address */ + uint32_t dst_ip; /**< Inner Destination IPv4 address */ + uint32_t tun_src_ip; /**< Tunnel Source IPv4 address */ + uint32_t tun_dst_ip; /**< Tunnel Source IPv4 address */ +} tun_db_entry_t; + +/** + * Tunnel database + */ +typedef struct tun_db_s { + uint32_t index; /**< Index of next available entry */ + tun_db_entry_t *list; /**< List of active entries */ + tun_db_entry_t array[MAX_DB]; /**< Entry storage */ +} tun_db_t; + +/** Initialize tun database global control structure */ +void init_tun_db(void); + +/** + * Create an tunnel DB entry + * + * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp" + * + * @param input Pointer to string describing tun + * + * @return 0 if successful else -1 + */ +int create_tun_db_entry(char *input); + +/** + * Display the tun DB + */ +void dump_tun_db(void); + +/** + * Find a matching tun DB entry + * + * @param ip_src Inner source IP address + * @param ip_dst Inner destination IP address + * + * @return pointer to tun DB entry else NULL + */ +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src, + uint32_t ip_dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/ipsec_crypto/odp_ipsec_sp_db.c b/example/ipsec_crypto/odp_ipsec_sp_db.c new file mode 100644 index 000000000..1e5820b47 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_sp_db.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#include +#include + +#include + +/** Global pointer to sp db */ +sp_db_t *sp_db; + +void init_sp_db(void) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("shm_sp_db", + sizeof(sp_db_t), + ODP_CACHE_LINE_SIZE, + 0); + + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Error: shared mem reserve failed.\n"); + exit(EXIT_FAILURE); + } + + sp_db = odp_shm_addr(shm); + + if (sp_db == NULL) { + ODPH_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(sp_db, 0, sizeof(*sp_db)); +} + +int create_sp_db_entry(char *input, odp_bool_t both_supported) +{ + int pos = 0; + char *local; + char *str; + char *save; + char *token; + sp_db_entry_t *entry = &sp_db->array[sp_db->index]; + + /* Verify we have a good entry */ + if (MAX_DB <= sp_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_subnet.addr, + &entry->src_subnet.mask); + break; + case 1: + parse_ipv4_string(token, + &entry->dst_subnet.addr, + &entry->dst_subnet.mask); + break; + case 2: + if (0 == strcmp(token, "in")) + entry->input = TRUE; + else + entry->input = FALSE; + break; + case 3: + if (0 == strcmp(token, "esp")) { + entry->esp = TRUE; + } else if (0 == strcmp(token, "ah")) { + entry->ah = TRUE; + } else if (0 == strcmp(token, "both")) { + entry->esp = TRUE; + entry->ah = TRUE; + } + break; + default: + printf("ERROR: extra token \"%s\" at position %d\n", + token, pos); + break; + } + + /* Advance to next position */ + pos++; + } + + /* Check if enabling both AH and ESP protocols is supported */ + if (!both_supported && (entry->ah && entry->esp)) { + printf("ERROR: enabling both AH and ESP is not supported\n"); + free(local); + return -1; + } + + /* Verify we parsed exactly the number of tokens we expected */ + if (4 != pos) { + printf("ERROR: \"%s\" contains %d tokens, expected 4\n", + input, + pos); + free(local); + return -1; + } + + /* Add route to the list */ + sp_db->index++; + entry->next = sp_db->list; + sp_db->list = entry; + + free(local); + return 0; +} + +void dump_sp_db_entry(sp_db_entry_t *entry) +{ + char src_subnet_str[MAX_STRING]; + char dst_subnet_str[MAX_STRING]; + + printf(" %s %s %s %s:%s\n", + ipv4_subnet_str(src_subnet_str, &entry->src_subnet), + ipv4_subnet_str(dst_subnet_str, &entry->dst_subnet), + entry->input ? "in" : "out", + entry->esp ? "esp" : "none", + entry->ah ? "ah" : "none"); +} + +void dump_sp_db(void) +{ + sp_db_entry_t *entry; + + printf("\n" + "Security policy table\n" + "---------------------\n"); + + for (entry = sp_db->list; NULL != entry; entry = entry->next) + dump_sp_db_entry(entry); +} diff --git a/example/ipsec_crypto/odp_ipsec_sp_db.h b/example/ipsec_crypto/odp_ipsec_sp_db.h new file mode 100644 index 000000000..878f3a7c4 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_sp_db.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_IPSEC_SP_DB_H_ +#define ODP_IPSEC_SP_DB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Security Policy (SP) data base entry + */ +typedef struct sp_db_entry_s { + struct sp_db_entry_s *next; /**< Next entry on list */ + ip_addr_range_t src_subnet; /**< Source IPv4 subnet/range */ + ip_addr_range_t dst_subnet; /**< Destination IPv4 subnet/range */ + odp_bool_t input; /**< Direction when applied */ + odp_bool_t esp; /**< Enable cipher (ESP) */ + odp_bool_t ah; /**< Enable authentication (AH) */ +} sp_db_entry_t; + +/** + * Security Policy (SP) data base global structure + */ +typedef struct sp_db_s { + uint32_t index; /**< Index of next available entry */ + sp_db_entry_t *list; /**< List of active entries */ + sp_db_entry_t array[MAX_DB]; /**< Entry storage */ +} sp_db_t; + +/** Global pointer to sp db */ +extern sp_db_t *sp_db; + +/** Initialize SP database global control structure */ +void init_sp_db(void); + +/** + * Create an SP DB entry + * + * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|[both])" + * + * @param input Pointer to a string describing SP + * @param both_supported Enabling both AH and ESP is supported + * + * @return 0 if successful else -1 + */ +int create_sp_db_entry(char *input, odp_bool_t both_supported); + +/** + * Display one SP DB entry + * + * @param entry Pointer to entry to display + */ +void dump_sp_db_entry(sp_db_entry_t *entry); + +/** + * Display the SP DB + */ +void dump_sp_db(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/ipsec_crypto/odp_ipsec_stream.c b/example/ipsec_crypto/odp_ipsec_stream.c new file mode 100644 index 000000000..d689c6198 --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_stream.c @@ -0,0 +1,678 @@ +/* Copyright (c) 2014-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +#define STREAM_MAGIC 0xBABE01234567CAFE + +#define LOOP_DEQ_COUNT 32 /**< packets to dequeue at once */ + +/** + * Stream packet header + */ +typedef struct ODP_PACKED stream_pkt_hdr_s { + odp_u64be_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) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("stream_db", + 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)); +} + +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; +} + +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); + + /* 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); + } +} + +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_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->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 = 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); + memset(data, 0, encrypt_len - payload_len); + data += encrypt_len - payload_len; + + 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(EVP_md5(), + entry->ah.key.data, + entry->ah.key.length, + (uint8_t *)ip, + auth_len, + hash, + NULL); + + memcpy(ah->icv, hash, 12); + } + + /* 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); + + /* 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) + 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]; + + /* 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, + 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 (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; +} diff --git a/example/ipsec_crypto/odp_ipsec_stream.h b/example/ipsec_crypto/odp_ipsec_stream.h new file mode 100644 index 000000000..b32f1d7cb --- /dev/null +++ b/example/ipsec_crypto/odp_ipsec_stream.h @@ -0,0 +1,135 @@ +/* Copyright (c) 2014-2018, 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 */ + uint32_t length; /**< Packet payload length */ + uint32_t created; /**< Number successfully created */ + uint32_t verified; /**< Number successfully verified */ + struct { + const char *intf; /**< Input interface name */ + odp_pktio_t pktio; /**< Input PktI/O interface */ + 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 { + const char *intf; /**< Output interface name */ + odp_pktio_t pktio; /**< Output PktI/O interface */ + 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 + * @param max_len Maximum packet length + * + * @return packet else ODP_PACKET_INVALID + */ +odp_packet_t create_ipv4_packet(stream_db_entry_t *stream, + uint8_t *dmac, + odp_pool_t pkt_pool, + uint32_t max_len); + +/** + * Verify an IPv4 packet received on a loop output queue + * + * @param stream Stream to verify the packet against + * @param pkt Packet to verify + * + * @return TRUE if packet verifies else FALSE + */ +odp_bool_t 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 removed and processed as if they had come from a normal + * packet interface. + * + * @return number of streams successfully processed + * @return <0 on failure + */ +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 + */ +odp_bool_t verify_stream_db_outputs(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 index 7bd8acdf8..a3cc1ddbe 100644 --- a/example/m4/configure.m4 +++ b/example/m4/configure.m4 @@ -23,8 +23,8 @@ AC_CONFIG_FILES([example/classifier/Makefile example/debug/Makefile example/generator/Makefile example/hello/Makefile - example/ipsec/Makefile example/ipsec_api/Makefile + example/ipsec_crypto/Makefile example/ipfragreass/Makefile example/ipsec_offload/Makefile example/l2fwd_simple/Makefile diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am index 15263f88e..3cc82516d 100644 --- a/platform/linux-generic/test/Makefile.am +++ b/platform/linux-generic/test/Makefile.am @@ -14,10 +14,10 @@ TESTS = validation/api/pktio/pktio_run.sh \ validation/api/pktio/pktio_run_tap.sh \ validation/api/shmem/shmem_linux$(EXEEXT) \ ipsec/ipsec_api_example.sh \ - ipsec/ipsec_example.sh + ipsec/ipsec_crypto_example.sh dist_check_SCRIPTS = ipsec/ipsec_api_example.sh \ - ipsec/ipsec_example.sh + ipsec/ipsec_crypto_example.sh test_SCRIPTS = $(dist_check_SCRIPTS) diff --git a/platform/linux-generic/test/ipsec/ipsec_crypto_example.sh b/platform/linux-generic/test/ipsec/ipsec_crypto_example.sh new file mode 100755 index 000000000..d99fc3bd2 --- /dev/null +++ b/platform/linux-generic/test/ipsec/ipsec_crypto_example.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# +# Copyright (c) 2019, Nokia +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# Skip IPsec example tests when there's no OpenSSL. +if [ -n "$WITH_OPENSSL" ] && [ ${WITH_OPENSSL} -eq 0 ]; then +echo "Crypto not supported. Skipping." +exit 77 +fi + +# Absolute path to the example binary. This is needed during distcheck, which +# keeps scripts and binaries in different directories (scripts are not copied +# into the distribution directory). +export IPSEC_EXAMPLE_PATH=$(pwd)/../../../example/ipsec_crypto + +declare -i RESULT=0 + +pushd $(dirname $0)/../../../../example/ipsec_crypto + +./odp_ipsec_crypto_run_simple.sh +RESULT+=$? + +./odp_ipsec_crypto_run_esp_out.sh +RESULT+=$? + +popd + +exit ${RESULT} diff --git a/platform/linux-generic/test/ipsec/ipsec_example.sh b/platform/linux-generic/test/ipsec/ipsec_example.sh deleted file mode 100755 index e38350c03..000000000 --- a/platform/linux-generic/test/ipsec/ipsec_example.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2019, Nokia -# All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# - -# Skip IPsec example tests when there's no OpenSSL. -if [ -n "$WITH_OPENSSL" ] && [ ${WITH_OPENSSL} -eq 0 ]; then -echo "Crypto not supported. Skipping." -exit 77 -fi - -# Absolute path to the example binary. This is needed during distcheck, which -# keeps scripts and binaries in different directories (scripts are not copied -# into the distribution directory). -export IPSEC_EXAMPLE_PATH=$(pwd)/../../../example/ipsec - -declare -i RESULT=0 - -pushd $(dirname $0)/../../../../example/ipsec - -./odp_ipsec_run_simple.sh -RESULT+=$? - -./odp_ipsec_run_esp_out.sh -RESULT+=$? - -popd - -exit ${RESULT} -- cgit v1.2.3