Message ID | 20170222122705.4960-1-nikhil.agarwal@linaro.org |
---|---|
State | Superseded |
Headers | show |
please do not define internal defines with ODP_ prefixes. We use that prefixes for API calls. Maxim. On 22 February 2017 at 15:27, Nikhil Agarwal <nikhil.agarwal@linaro.org> wrote: > Signed-off-by: Nikhil Agarwal <nikhil.agarwal@linaro.org> > --- > example/Makefile.am | 1 + > example/ipsec_offload/.gitignore | 1 + > example/ipsec_offload/Makefile.am | 19 + > example/ipsec_offload/odp_ipsec_offload.c | 871 > +++++++++++++++++++++++ > example/ipsec_offload/odp_ipsec_offload_cache.c | 148 ++++ > example/ipsec_offload/odp_ipsec_offload_cache.h | 78 ++ > example/ipsec_offload/odp_ipsec_offload_fwd_db.c | 223 ++++++ > example/ipsec_offload/odp_ipsec_offload_fwd_db.h | 198 ++++++ > example/ipsec_offload/odp_ipsec_offload_misc.h | 384 ++++++++++ > example/ipsec_offload/odp_ipsec_offload_sa_db.c | 361 ++++++++++ > example/ipsec_offload/odp_ipsec_offload_sa_db.h | 126 ++++ > example/ipsec_offload/odp_ipsec_offload_sp_db.c | 166 +++++ > example/ipsec_offload/odp_ipsec_offload_sp_db.h | 72 ++ > example/ipsec_offload/run_left | 14 + > example/ipsec_offload/run_right | 14 + > example/m4/configure.m4 | 1 + > 16 files changed, 2677 insertions(+) > create mode 100644 example/ipsec_offload/.gitignore > create mode 100644 example/ipsec_offload/Makefile.am > create mode 100644 example/ipsec_offload/odp_ipsec_offload.c > create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.c > create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.h > create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.c > create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.h > create mode 100644 example/ipsec_offload/odp_ipsec_offload_misc.h > create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.c > create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.h > create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.c > create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.h > create mode 100644 example/ipsec_offload/run_left > create mode 100644 example/ipsec_offload/run_right > > diff --git a/example/Makefile.am b/example/Makefile.am > index dfc07b6..24b9e52 100644 > --- a/example/Makefile.am > +++ b/example/Makefile.am > @@ -2,6 +2,7 @@ SUBDIRS = classifier \ > generator \ > hello \ > ipsec \ > + ipsec_offload \ > l2fwd_simple \ > l3fwd \ > packet \ > diff --git a/example/ipsec_offload/.gitignore b/example/ipsec_offload/. > gitignore > new file mode 100644 > index 0000000..2fc73aa > --- /dev/null > +++ b/example/ipsec_offload/.gitignore > @@ -0,0 +1 @@ > +odp_ipsec_offload > diff --git a/example/ipsec_offload/Makefile.am b/example/ipsec_offload/ > Makefile.am > new file mode 100644 > index 0000000..a61b923 > --- /dev/null > +++ b/example/ipsec_offload/Makefile.am > @@ -0,0 +1,19 @@ > +include $(top_srcdir)/example/Makefile.inc > + > +bin_PROGRAMS = odp_ipsec_offload$(EXEEXT) > +odp_ipsec_offload_LDFLAGS = $(AM_LDFLAGS) -static > +odp_ipsec_offload_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example > + > +noinst_HEADERS = \ > + $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_cache.h > \ > + $(top_srcdir)/example/ipsec_ > offload/odp_ipsec_offload_fwd_db.h \ > + $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_misc.h > \ > + $(top_srcdir)/example/ipsec_ > offload/odp_ipsec_offload_sa_db.h \ > + $(top_srcdir)/example/ipsec_ > offload/odp_ipsec_offload_sp_db.h \ > + $(top_srcdir)/example/example_debug.h > + > +dist_odp_ipsec_offload_SOURCES = odp_ipsec_offload.c \ > + odp_ipsec_offload_sa_db.c \ > + odp_ipsec_offload_sp_db.c \ > + odp_ipsec_offload_fwd_db.c \ > + odp_ipsec_offload_cache.c > diff --git a/example/ipsec_offload/odp_ipsec_offload.c > b/example/ipsec_offload/odp_ipsec_offload.c > new file mode 100644 > index 0000000..4a494d0 > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload.c > @@ -0,0 +1,871 @@ > +/* Copyright (c) 2017, Linaro Limited > + * Copyright (C) 2017 NXP > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/** > + * @file > + * > + * @example odp_ipsec_offload.c ODP basic packet IO cross connect with > IPsec > + * test application > + */ > + > +#define _DEFAULT_SOURCE > +/* enable strtok */ > +#define _POSIX_C_SOURCE 200112L > +#include <stdlib.h> > +#include <getopt.h> > +#include <unistd.h> > + > +#include <example_debug.h> > + > +#include <odp_api.h> > +#include <odp/helper/linux.h> > +#include <odp/helper/eth.h> > +#include <odp/helper/ip.h> > +#include <odp/helper/icmp.h> > +#include <odp/helper/udp.h> > +#include <odp/helper/ipsec.h> > + > +#include <stdbool.h> > +#include <sys/socket.h> > +#include <net/if.h> > +#include <sys/ioctl.h> > +#include <sys/socket.h> > +#include <netpacket/packet.h> > +#include <net/ethernet.h> > +#include <arpa/inet.h> > + > +#include <odp_ipsec_offload_misc.h> > +#include <odp_ipsec_offload_sa_db.h> > +#include <odp_ipsec_offload_sp_db.h> > +#include <odp_ipsec_offload_fwd_db.h> > +#include <odp_ipsec_offload_cache.h> > + > +#define MAX_WORKERS 32 /**< maximum number of worker threads */ > + > +/** > + * Parsed command line application arguments > + */ > +typedef struct { > + int cpu_count; > + int flows; > + int if_count; /**< Number of interfaces to be used */ > + char **if_names; /**< Array of pointers to interface names > */ > + char *if_str; /**< Storage for interface names */ > + int queue_type; /**< Queue synchronization type*/ > +} appl_args_t; > +/** > + * Grouping of both parsed CL args and thread specific args - alloc > together > + */ > +typedef struct { > + /** Application (parsed) arguments */ > + appl_args_t appl; > +} args_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); > + > +/** Global pointer to args */ > +static args_t *args; > + > +/** > + * 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) > + > +static odp_pool_t pkt_pool = ODP_POOL_INVALID; > + > +/** Synchronize threads before packet processing begins */ > +static odp_barrier_t sync_barrier; > + > +/** > + * 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; > + > +#define MAX_COMPL_QUEUES 32 > +#define GET_THR_QUEUE_ID(x) ((odp_thread_id()-1) % (x)) > + > +/** Atomic queue IPSEC completion events */ > +static odp_queue_t completionq[MAX_COMPL_QUEUES]; > + > +static int num_compl_queues; > +static int num_workers; > + > + > +/** > + * Calculate hash value on given 2-tuple i.e. sip, dip > + * > + * @param ip_src Source IP Address > + * @param ip_dst Destination IP Address > + * > + * @return Resultant hash value > + */ > +static inline uint64_t calculate_flow_hash(uint32_t ip_src, uint32_t > ip_dst) > +{ > + uint64_t hash = 0; > + > + ip_dst += JHASH_GOLDEN_RATIO; > + ODP_BJ3_MIX(ip_src, ip_dst, hash); > + return hash; > +} > + > +/** > + * IPsec pre argument processing intialization > + */ > +static > +void ipsec_init_pre(void) > +{ > + /* 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 > + */ > +static > +void ipsec_init_post(void) > +{ > + sp_db_entry_t *entry; > + int queue_id = 0; > + > + /* 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; > + queue_id %= num_workers; > + if (num_compl_queues < num_workers) > + num_compl_queues++; > + queue_id++; > + 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, > + entry->input, > + completionq[queue_id > - 1])) { > + EXAMPLE_ABORT("Error: IPSec cache entry > failed.\n"); > + } > + } else { > + printf(" WARNING: SA not found for SP\n"); > + dump_sp_db_entry(entry); > + } > + } > +} > + > +/** > + * Initialize interface > + * > + * Initialize ODP pktio and queues, query MAC address and update > + * forwarding database. > + * > + * @param intf Interface name string > + * @param queue_type Type of queue to configure. > + */ > +static void initialize_intf(char *intf, int queue_type) > +{ > + odp_pktio_t pktio; > + odp_pktout_queue_t pktout; > + int ret; > + uint8_t src_mac[ODPH_ETHADDR_LEN]; > + odp_pktio_param_t pktio_param; > + odp_pktio_capability_t capa; > + odp_pktin_queue_param_t pktin_param; > + > + odp_pktio_param_init(&pktio_param); > + > + 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, pkt_pool, &pktio_param); > + if (ODP_PKTIO_INVALID == pktio) { > + EXAMPLE_ABORT("Error: pktio create failed for %s\n", intf); > + } > + > + odp_pktin_queue_param_init(&pktin_param); > + > + ret = odp_pktio_capability(pktio, &capa); > + if (ret != 0) > + EXAMPLE_ABORT("Error: Unable to get pktio capability > %s\n", intf); > + > + pktin_param.queue_param.type = ODP_QUEUE_TYPE_SCHED; > + pktin_param.queue_param.sched.sync = queue_type; > + pktin_param.queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT; > + pktin_param.num_queues = capa.max_input_queues; > + > + if (pktin_param.num_queues > 1) > + pktin_param.hash_enable = 1; > + > + if (odp_pktin_queue_config(pktio, &pktin_param)) > + EXAMPLE_ABORT("Error: pktin config failed for %s\n", intf); > + > + if (odp_pktout_queue_config(pktio, NULL)) > + EXAMPLE_ABORT("Error: pktout config failed for %s\n", > intf); > + > + if (odp_pktout_queue(pktio, &pktout, 1) != 1) > + EXAMPLE_ABORT("Error: failed to get pktout queue for > %s\n", intf); > + > + ret = odp_pktio_start(pktio); > + if (ret) { > + EXAMPLE_ABORT("Error: unable to start %s\n", intf); > + } > + > + /* Read the source MAC address for this interface */ > + ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac)); > + if (ret < 0) { > + EXAMPLE_ABORT("Error: failed during MAC address get for > %s\n", > + intf); > + } > + > + printf("Created pktio:%02" PRIu64 "\n", odp_pktio_to_u64(pktio)); > + > + /* Resolve any routes using this interface for output */ > + resolve_fwd_db(intf, pktout, src_mac); > +} > + > +/** > + * Packet Processing - Input verification > + * > + * @param pkt Packet to inspect > + * > + * @return PKT_CONTINUE if good, supported packet else PKT_DROP > + */ > +static pkt_disposition_e do_input_verify(odp_packet_t pkt) > +{ > + if (odp_unlikely(odp_packet_has_error(pkt))) { > + odp_packet_free(pkt); > + return PKT_DROP; > + } > + > + if (!odp_packet_has_eth(pkt)) { > + odp_packet_free(pkt); > + return PKT_DROP; > + } > + > + if (!odp_packet_has_ipv4(pkt)) { > + odp_packet_free(pkt); > + return PKT_DROP; > + } > + > + return PKT_CONTINUE; > +} > + > +/** > + * Packet Processing - Route lookup in forwarding database > + * > + * @param pkt Packet to route > + * > + * @return PKT_CONTINUE if route found else PKT_DROP > + */ > +static > +pkt_disposition_e do_route_fwd_db(odp_packet_t pkt) > +{ > + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, > NULL); > + fwd_db_entry_t *fwd_entry; > + ipsec_cache_entry_t *ipsec_entry; > + odp_ipsec_op_param_t params; > + uint32_t sip, dip; > + uint64_t hash; > + odp_flow_entry_t *flow = NULL; > + > + if (ip->ttl > 1) { > + ip->ttl -= 1; > + if (ip->chksum >= odp_cpu_to_be_16(0xffff - 0x100)) > + ip->chksum += odp_cpu_to_be_16(0x100) + 1; > + else > + ip->chksum += odp_cpu_to_be_16(0x100); > + } else { > + odp_packet_free(pkt); > + return PKT_DROP; > + } > + > + sip = odp_be_to_cpu_32(ip->src_addr); > + dip = odp_be_to_cpu_32(ip->dst_addr); > + > + hash = calculate_flow_hash(sip, dip); > + > + flow = odp_route_flow_lookup_in_bucket(sip, dip, > + &flow_table[hash & > (bucket_count - 1)]); > + if (flow) { > +do_opt: > + odp_packet_user_ptr_set(pkt, &flow->out_port); > + if (flow->out_port.sa == ODP_IPSEC_SA_INVALID) > + return PKT_CONTINUE; > + > + /* Initialize parameters block */ > + params.sa = &flow->out_port.sa; > + params.pkt = &pkt; > + params.opt = NULL; > + params.num_pkt = 1; > + params.num_sa = 1; > + params.num_opt = 1; > + > + /* Issue ipsec request */ > + if (odp_unlikely(odp_ipsec_out_enq(¶ms) < 0)) { > + EXAMPLE_DBG("Unable to out enqueue\n"); > + odp_packet_free(pkt); > + return PKT_DROP; > + } > + return PKT_POSTED; > + } else { > + /*Check into Routing table*/ > + fwd_entry = find_fwd_db_entry(dip); > + if (fwd_entry) { > + /*Entry found. Updated in Flow table first.*/ > + flow = calloc(1, sizeof(odp_flow_entry_t)); > + if (!flow) { > + EXAMPLE_ABORT("Failure to allocate > memory"); > + } > + flow->l3_src = sip; > + flow->l3_dst = dip; > + flow->out_port.pktout = fwd_entry->pktout; > + memcpy(flow->out_port.addr.addr, > fwd_entry->src_mac, ODPH_ETHADDR_LEN); > + memcpy(flow->out_port.next_hop_addr.addr, > fwd_entry->dst_mac, ODPH_ETHADDR_LEN); > + ipsec_entry = find_ipsec_cache_entry_out(sip, > dip); > + if (ipsec_entry) > + flow->out_port.sa = ipsec_entry->sa; > + else > + flow->out_port.sa = ODP_IPSEC_SA_INVALID; > + flow->next = NULL; > + /*Insert new flow into flow cache table*/ > + odp_route_flow_insert_in_bucket(flow, > &flow_table[hash & (bucket_count - 1)]); > + goto do_opt; > + } else { > + EXAMPLE_DBG("No flow match found. Packet is > dropped.\n"); > + odp_packet_free(pkt); > + return PKT_DROP; > + > + } > + } > +} > + > + > +/** > + * Packet Processing - Input IPsec packet classification > + * > + * Verify the received packet has IPsec headers, > + * if so issue ipsec request else skip. > + * > + * @param pkt Packet to classify > + * > + * @return PKT_CONTINUE if done else PKT_POSTED > + */ > +static > +pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt) > +{ > + odp_ipsec_op_param_t params; > + > + if (!odp_packet_has_ipsec(pkt)) > + return PKT_CONTINUE; > + > + /* Initialize parameters block */ > + params.pkt = &pkt; > + params.num_pkt = 1; > + params.num_sa = 0; > + params.num_opt = 0; > + params.opt = NULL; > + > + /* Issue ipsec request */ > + if (odp_unlikely(odp_ipsec_in_enq(¶ms) < 0)) { > + EXAMPLE_DBG("Unable to in enqueue\n"); > + odp_packet_free(pkt); > + return PKT_DROP; > + } > + return PKT_POSTED; > +} > +/** > + * Packet IO worker thread > + * > + * Loop calling odp_schedule to obtain packet from the two sources, > + * and continue processing the packet. > + * > + * - Input interfaces (i.e. new work) > + * - Per packet ipsec API completion queue > + * > + * @param arg Required by "odph_linux_pthread_create", unused > + * > + * @return NULL (should never return) > + */ > +static > +void *pktio_thread(void *arg EXAMPLE_UNUSED) > +{ > + int thr; > + odp_packet_t pkt; > + odp_pktout_queue_t out_queue; > + odp_out_entry_t *out_port; > + odp_event_t ev = ODP_EVENT_INVALID; > + thr = odp_thread_id(); > + > + printf("Pktio thread [%02i] starts\n", thr); > + odp_barrier_wait(&sync_barrier); > + > + /* Loop packets */ > + for (;;) { > + pkt_disposition_e rc; > + > + ev = odp_schedule(NULL, ODP_SCHED_WAIT); > + /* Use schedule to get event from any input queue */ > + /* Determine new work versus completion */ > + if (ODP_EVENT_PACKET == odp_event_type(ev)) { > + pkt = odp_packet_from_event(ev); > + > + rc = do_input_verify(pkt); > + if (odp_unlikely(rc)) > + continue; > + > + rc = do_ipsec_in_classify(pkt); > + if (rc) > + continue; > + > + rc = do_route_fwd_db(pkt); > + if (rc) > + continue; > + > + out_port = (odp_out_entry_t > *)odp_packet_user_ptr(pkt); > + out_queue = (odp_pktout_queue_t)out_port->pktout; > + > + if (odp_unlikely(odp_pktout_send(out_queue, &pkt, > 1) < 0)) > + odp_packet_free(pkt); > + > + } else if (ODP_EVENT_IPSEC_RESULT == odp_event_type(ev)) { > + odp_ipsec_op_result_t result; > + odp_ipsec_packet_result_t res; > + odph_ethhdr_t *eth; > + odp_packet_t out_pkt; > + > + result.pkt = &out_pkt; > + result.res = &res; > + > + if (odp_unlikely(odp_ipsec_result(&result, ev) < > 0)) { > + EXAMPLE_DBG("Error Event\n"); > + odp_packet_free((odp_packet_t)ev); > + continue; > + } > + > + if (odp_unlikely(res.status.all)) { > + odp_packet_free((odp_packet_t)ev); > + continue; > + } > + > + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t > *)odp_packet_l3_ptr(out_pkt, NULL); > + > + if (ip->proto != IPPROTO_ESP) { > + rc = do_route_fwd_db(out_pkt); > + if (odp_unlikely(rc)) > + continue; > + } > + > + out_port = (odp_out_entry_t > *)odp_packet_user_ptr(out_pkt); > + out_queue = (odp_pktout_queue_t)out_port->pktout; > + > + eth = (odph_ethhdr_t *)((void *)ip - > sizeof(odph_ethhdr_t)); > + eth->dst = out_port->next_hop_addr; > + eth->src = out_port->addr; > + eth->type = odp_cpu_to_be_16(0x800); > + > + if (odp_unlikely(odp_pktout_send(out_queue, > &out_pkt, 1) < 0)) > + odp_packet_free(out_pkt); > + } else { > + EXAMPLE_DBG("Invalid Event\n"); > + odp_packet_free((odp_packet_t)ev); > + continue; > + } > + } > + > + /* unreachable */ > + return NULL; > +} > + > +/** > + * ODP ipsec proto example main function > + */ > +int > +main(int argc, char *argv[]) > +{ > + odph_linux_pthread_t thread_tbl[MAX_WORKERS]; > + int i; > + odp_shm_t shm; > + odp_cpumask_t cpumask; > + char cpumaskstr[ODP_CPUMASK_STR_SIZE]; > + odp_pool_param_t params; > + odp_queue_param_t qparam; > + odp_instance_t instance; > + odph_linux_thr_params_t thr_params; > + odp_ipsec_config_t config; > + odp_ipsec_capability_t capa; > + > + /*Validate if user has passed only help option*/ > + if (argc == 2) { > + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { > + usage(argv[0]); > + exit(EXIT_SUCCESS); > + } > + } > + > + /* Initialize ODP before calling anything else */ > + if (odp_init_global(&instance, NULL, NULL)) { > + EXAMPLE_ABORT("Error: ODP global init failed.\n"); > + } > + /* Initialize this thread */ > + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { > + EXAMPLE_ABORT("Error: ODP local init failed.\n"); > + } > + /* Reserve memory for arguments from shared memory */ > + shm = odp_shm_reserve("shm_args", sizeof(args_t), > + ODP_CACHE_LINE_SIZE, 0); > + args = odp_shm_addr(shm); > + > + if (NULL == args) { > + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); > + } > + memset(args, 0, sizeof(*args)); > + > + /* Must init our databases before parsing args */ > + ipsec_init_pre(); > + init_fwd_db(); > + > + /* Parse and store the application arguments */ > + parse_args(argc, argv, &args->appl); > + > + /*Initialize route table for user given parameter*/ > + odp_init_routing_table(); > + > + /* Print both system and application information */ > + print_info(NO_PATH(argv[0]), &args->appl); > + > + if (odp_ipsec_capability(&capa)) > + EXAMPLE_ABORT("Error: Capability not configured.\n"); > + > + odp_ipsec_config_init(&config); > + > + if (capa.op_mode_async && (capa.op_mode_async >= > capa.op_mode_sync)) > + config.op_mode = ODP_IPSEC_OP_MODE_ASYNC; > + else > + EXAMPLE_ABORT("Error: Sync mode not supported.\n"); > + > + if (odp_ipsec_config(&config)) > + EXAMPLE_ABORT("Error: IPSec not configured.\n"); > + > + /* Default to system CPU count unless user specified */ > + num_workers = MAX_WORKERS; > + if (args->appl.cpu_count && args->appl.cpu_count <= MAX_WORKERS) > + num_workers = args->appl.cpu_count; > + > + /* > + * By default CPU #0 runs Linux kernel background tasks. > + * Start mapping thread from CPU #1 > + */ > + num_workers = odp_cpumask_default_worker(&cpumask, num_workers); > + (void)odp_cpumask_to_str(&cpumask, cpumaskstr, > sizeof(cpumaskstr)); > + > + /* > + * Create completion queues > + */ > + odp_queue_param_init(&qparam); > + qparam.type = ODP_QUEUE_TYPE_SCHED; > + qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; > + qparam.sched.sync = args->appl.queue_type; > + qparam.sched.group = ODP_SCHED_GROUP_ALL; > + > + for (i = 0; i < num_workers; i++) { > + completionq[i] = odp_queue_create("completion", &qparam); > + if (ODP_QUEUE_INVALID == completionq[i]) { > + EXAMPLE_ABORT("Error: completion queue creation > failed\n"); > + } > + } > + 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(&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; > + > + pkt_pool = odp_pool_create("packet_pool", ¶ms); > + > + if (ODP_POOL_INVALID == pkt_pool) { > + EXAMPLE_ABORT("Error: packet pool create failed.\n"); > + } > + > + ipsec_init_post(); > + > + /* Initialize interfaces (which resolves FWD DB entries */ > + for (i = 0; i < args->appl.if_count; i++) { > + initialize_intf(args->appl.if_names[i], > args->appl.queue_type); > + } > + > + printf(" Configured queues SYNC type: [%s]\n", > (args->appl.queue_type == 0)? > + > "PARALLEL":(args->appl.queue_type == 1)? > + > "ATOMIC":"ORDERED"); > + 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; > + > + /* Create and initialize worker threads */ > + odph_linux_pthread_create(thread_tbl, &cpumask, > + &thr_params); > + odph_linux_pthread_join(thread_tbl, num_workers); > + > + free(args->appl.if_names); > + free(args->appl.if_str); > + 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 struct option longopts[] = { > + {"count", required_argument, NULL, 'c'}, > + {"interface", required_argument, NULL, 'i'}, /* return > 'i' */ > + {"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' */ > + {"flows", no_argument, NULL, 'f'}, /* return > 'f' */ > + {"queue type", required_argument, NULL, 'q'}, /* return > 'q' */ > + {"help", no_argument, NULL, 'h'}, /* return > 'h' */ > + {NULL, 0, NULL, 0} > + }; > + > + appl_args->flows = 1; > + appl_args->queue_type = ODP_SCHED_SYNC_ATOMIC; > + > + while (!rc) { > + opt = getopt_long(argc, argv, "+c:i:h:r:p:a:e:t:s:q:f:", > + longopts, &long_index); > + if (opt < 0) > + break; /* No more options */ > + switch (opt) { > + case 'f': > + appl_args->flows = atoi(optarg); > + if (appl_args->flows > 256) { > + printf("Maximum acceptable value for -f is > 256\n"); > + rc = -1; > + } > + if (optind != 3) { > + printf("-f must be the 1st argument of the > command\n"); > + rc = -1; > + } > + EXAMPLE_DBG("Bucket count = %d\n", bucket_count); > + break; > + case 'c': > + appl_args->cpu_count = atoi(optarg); > + break; > + case 'i': > + /* parse packet-io interface names */ > + 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; token = strtok(NULL, ","), i++); > + appl_args->if_count = i; > + if (!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 > *)); > + if (!appl_args->if_names) { > + EXAMPLE_ABORT("Memory allocation > failure\n"); > + } > + /* Store the if names (reset names string) */ > + strcpy(appl_args->if_str, optarg); > + for (token = strtok(appl_args->if_str, ","), i = 0; > + token; token = strtok(NULL, ","), i++) { > + appl_args->if_names[i] = token; > + } > + break; > + case 'r': > + rc = create_fwd_db_entry(optarg, > appl_args->if_names, > + appl_args->if_count, > appl_args->flows); > + break; > + case 'p': > + rc = create_sp_db_entry(optarg, appl_args->flows); > + break; > + case 'a': > + rc = create_sa_db_entry(optarg, FALSE, > appl_args->flows); > + break; > + case 'e': > + rc = create_sa_db_entry(optarg, TRUE, > appl_args->flows); > + break; > + case 't': > + rc = create_tun_db_entry(optarg, appl_args->flows); > + break; > + case 'q': > + i = atoi(optarg); > + if (i > ODP_SCHED_SYNC_ORDERED || i < > ODP_SCHED_SYNC_PARALLEL) { > + printf("Invalid queue type: setting > default to atomic"); > + break; > + } > + appl_args->queue_type = i; > + 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; > + > + printf("\n" > + "ODP system info\n" > + "---------------\n" > + "ODP API version: %s\n" > + "CPU model: %s\n" > + "CPU freq (hz): %"PRIu64"\n" > + "Cache line size: %i\n" > + "CPU count: %i\n" > + "\n", > + odp_version_api_str(), odp_cpu_model_str(), > odp_cpu_hz_max(), > + odp_sys_cache_line_size(), odp_cpu_count()); > + printf("Running ODP application: \"%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" > + "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:(md5|null):SPI:Key128\n" > + " -t, --tun SrcIP:DstIP:TunSrcIP:TunDstIP\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" > + " -t 192.168.111.2:192.168.222.2:192.168.150.1:192 > .168.150.2\n" > + "\n" > + "Optional OPTIONS\n" > + " -f, --flows <number> routes count.\n" > + " -c, --count <number> CPU count.\n" > + " -q specify the queue type\n" > + " 0: ODP_SCHED_SYNC_PARALLEL\n" > + " 1: ODP_SCHED_SYNC_ATOMIC\n" > + " 2: ODP_SCHED_SYNC_ORDERED\n" > + " default is ODP_SCHED_SYNC_ATOMIC\n" > + " -h, --help Display help and exit.\n" > + "\n", NO_PATH(progname), NO_PATH(progname) > + ); > +} > diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.c > b/example/ipsec_offload/odp_ipsec_offload_cache.c > new file mode 100644 > index 0000000..5b6a036 > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_cache.c > @@ -0,0 +1,148 @@ > +/* > + * Copyright (c) 2017 NXP. All rights reserved. > + */ > +/* Copyright (c) 2017, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#include <stdlib.h> > +#include <string.h> > + > +#include <example_debug.h> > + > +#include <odp.h> > + > +#include <odp/helper/ipsec.h> > +#include <odp/helper/ip.h> > + > +#include <odp_ipsec_offload_cache.h> > + > +/** Global pointer to ipsec_cache db */ > +ipsec_cache_t *ipsec_cache; > + > +#define IPDEFTTL 64 > + > +void init_ipsec_cache(void) > +{ > + odp_shm_t shm; > + > + shm = odp_shm_reserve("shm_ipsec_cache", > + sizeof(ipsec_cache_t), > + ODP_CACHE_LINE_SIZE, > + 0); > + > + ipsec_cache = odp_shm_addr(shm); > + > + if (ipsec_cache == NULL) { > + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); > + } > + memset(ipsec_cache, 0, sizeof(*ipsec_cache)); > +} > + > +int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa, > + sa_db_entry_t *auth_sa, > + tun_db_entry_t *tun, > + odp_bool_t in, > + odp_queue_t completionq) > +{ > + odp_ipsec_sa_param_t sa_params; > + ipsec_cache_entry_t *entry; > + odp_ipsec_sa_t sa; > + uint32_t src_ip, dst_ip; > + > + odp_ipsec_sa_param_init(&sa_params); > + > + /* 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 (!tun) { > + printf("\n TRANSPORT MODE not supported"); > + return -1; > + } > + > + /* Setup parameters and call ipsec library to create sa */ > + if (in) { > + sa_params.dir = ODP_IPSEC_DIR_INBOUND; > + sa_params.lookup_mode = ODP_IPSEC_LOOKUP_IN_UNIQUE_SA; > + } else { > + sa_params.dir = ODP_IPSEC_DIR_OUTBOUND; > + sa_params.lookup_mode = ODP_IPSEC_LOOKUP_DISABLED; > + } > + > + sa_params.dest_queue = completionq; > + sa_params.mode = ODP_IPSEC_MODE_TUNNEL; > + > + /* Cipher */ > + if (cipher_sa) { > + sa_params.crypto.cipher_alg = cipher_sa->alg.u.cipher; > + sa_params.crypto.cipher_key.data = cipher_sa->key.data; > + sa_params.crypto.cipher_key.length = > cipher_sa->key.length; > + sa_params.spi = cipher_sa->spi; > + } else { > + sa_params.crypto.cipher_alg = ODP_CIPHER_ALG_NULL; > + } > + > + /* Auth */ > + if (auth_sa) { > + sa_params.crypto.auth_alg = auth_sa->alg.u.auth; > + sa_params.crypto.auth_key.data = auth_sa->key.data; > + sa_params.crypto.auth_key.length = auth_sa->key.length; > + } else { > + sa_params.crypto.auth_alg = ODP_AUTH_ALG_NULL; > + } > + > + src_ip = odp_cpu_to_be_32(tun->tun_src_ip); > + dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip); > + sa_params.tunnel.type = ODP_IPSEC_TUNNEL_IPV4; > + sa_params.tunnel.ipv4.src_addr = &src_ip; > + sa_params.tunnel.ipv4.dst_addr = &dst_ip; > + sa_params.tunnel.ipv4.ttl = IPDEFTTL; > + sa_params.tunnel.ipv4.dscp = 0; > + sa_params.tunnel.ipv4.df = 1; > + > + sa = odp_ipsec_sa_create(&sa_params); > + if (sa == ODP_IPSEC_SA_INVALID) > + return -1; > + > + /* Copy selector IPs in cache entry*/ > + if (cipher_sa) { > + entry->src_ip = cipher_sa->src_ip; > + entry->dst_ip = cipher_sa->dst_ip; > + } else if (auth_sa) { > + entry->src_ip = auth_sa->src_ip; > + entry->dst_ip = auth_sa->dst_ip; > + } > + > + /* Initialize state */ > + entry->sa = sa; > + > + /* 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_out(uint32_t src_ip, > + uint32_t dst_ip) > +{ > + 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; > +} > diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.h > b/example/ipsec_offload/odp_ipsec_offload_cache.h > new file mode 100644 > index 0000000..65f4dda > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_cache.h > @@ -0,0 +1,78 @@ > +/* Copyright (c) 2017, 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 <odp.h> > +#include <odp/helper/ipsec.h> > + > +#include <odp_ipsec_offload_misc.h> > +#include <odp_ipsec_offload_sa_db.h> > + > +/** > + * IPsec cache data base entry > + */ > +typedef struct ipsec_cache_entry_s { > + struct ipsec_cache_entry_s *next; /**< Next entry on > list */ > + uint32_t src_ip; /**< Source v4 > address */ > + uint32_t dst_ip; /**< Destination > v4 address */ > + odp_ipsec_sa_t sa; /**< IPSec sa > handle */ > +} 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 in Direction (input versus output) > + * @param completionq Completion queue > + * > + * @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, > + odp_bool_t in, > + odp_queue_t completionq); > + > +/** > + * Find a matching IPsec cache entry for output packet > + * > + * @param src_ip Source IPv4 address > + * @param dst_ip Destination IPv4 address > + * > + * @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); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif > diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.c > b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c > new file mode 100644 > index 0000000..860b3ee > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c > @@ -0,0 +1,223 @@ > +/* Copyright (c) 2017, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/* enable strtok */ > +#define _POSIX_C_SOURCE 200112L > + > +#include <stdlib.h> > +#include <string.h> > + > +#include <example_debug.h> > +#include <odp.h> > + > +#include <odp_ipsec_offload_fwd_db.h> > + > +/** > + * Pointer to Flow cache table > + */ > +flow_bucket_t *flow_table; > + > +/** > + * bucket count. It will be updated with user argument if provided > + */ > +uint32_t bucket_count = ODP_DEFAULT_BUCKET_COUNT; > + > +/** Global pointer to fwd db */ > +fwd_db_t *fwd_db; > + > +void odp_init_routing_table(void) > +{ > + odp_shm_t hash_shm; > + uint32_t i; > + flow_bucket_t *bucket; > + > + /*Reserve memory for Routing hash table*/ > + hash_shm = odp_shm_reserve("route_table", > + sizeof(flow_bucket_t) * bucket_count, > + ODP_CACHE_LINE_SIZE, 0); > + flow_table = odp_shm_addr(hash_shm); > + if (!flow_table) { > + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); > + } > + /*Inialize Locks*/ > + for (i = 0; i < bucket_count; i++) { > + bucket = &flow_table[i]; > + LOCK_INIT(&bucket->lock); > + } > + > + memset(flow_table, 0, bucket_count * sizeof(flow_bucket_t)); > +} > + > +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); > + > + fwd_db = odp_shm_addr(shm); > + > + if (fwd_db == NULL) { > + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); > + } > + memset(fwd_db, 0, sizeof(*fwd_db)); > +} > + > +int create_fwd_db_entry(char *input, char **if_names, int if_count, int > entries) > +{ > + int pos = 0, i, match = 0, count = 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; > + > + count++; > + > + while (count < entries) { > + fwd_db_entry_t *new_entry = &fwd_db->array[fwd_db->index]; > + > + /* Verify we haven't run out of space */ > + if (MAX_DB <= fwd_db->index) > + return -1; > + > + new_entry->subnet.addr = entry->subnet.addr + count; > + new_entry->subnet.mask = entry->subnet.mask; > + strncpy(new_entry->oif, entry->oif, OIF_LEN - 1); > + new_entry->oif[OIF_LEN - 1] = 0; > + new_entry->dst_mac[0] = entry->dst_mac[0]; > + new_entry->dst_mac[1] = entry->dst_mac[1]; > + new_entry->dst_mac[2] = entry->dst_mac[2]; > + new_entry->dst_mac[3] = entry->dst_mac[3]; > + new_entry->dst_mac[4] = entry->dst_mac[4]; > + new_entry->dst_mac[5] = entry->dst_mac[5]; > + > + /* Add route to the list */ > + fwd_db->index++; > + new_entry->next = fwd_db->list; > + fwd_db->list = new_entry; > + count++; > + } > + > + free(local); > + return 0; > +} > + > +void resolve_fwd_db(char *intf, 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->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_offload/odp_ipsec_offload_fwd_db.h > b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h > new file mode 100644 > index 0000000..2f42596 > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h > @@ -0,0 +1,198 @@ > +/* Copyright (c) 2017, 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 <odp.h> > +#include <odp/helper/eth.h> > +#include <odp_ipsec_offload_misc.h> > + > +#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_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; > + > +/** > + * Flow cache table entry > + */ > +typedef struct { > + void *next; /**< Pointer to next flow > in list*/ > + uint32_t l3_src; /**< Source IP Address*/ > + uint32_t l3_dst; /**< Destination IP > Address*/ > + odp_out_entry_t out_port; /**< Out interface of > matching flow*/ > +} odp_flow_entry_t; > + > +/** > + * Flow cache table bucket > + */ > +typedef struct { > + odp_spinlock_t lock; /**< Bucket lock*/ > + odp_flow_entry_t *next; /**< Pointer to first flow entry > in bucket*/ > +} flow_bucket_t; > + > +/** > +* Pointers to Flow cache tables > +*/ > +extern flow_bucket_t *flow_table; > + > +extern flow_bucket_t *ipsec_out_flow_table; > + > +extern flow_bucket_t *ipsec_in_flow_table; > + > +/** > + * Number of buckets in hash table > + */ > +extern uint32_t bucket_count; > + > +/* > + * Allocate and Initialize routing table with default Route entries. > + * > + */ > +void odp_init_routing_table(void); > + > +/* > + * Searches flow entry in given hash bucket according to given 5-tuple > information > + * > + * @param sip Source IP Address > + * @param dip Destination IP Address > + * @param sport Source Port Number > + * @param dport Destination Port Number > + * @param proto IP protocol > + * @param bucket Hash Bucket > + * > + * @return Matching flow entry > + */ > +static inline odp_flow_entry_t *odp_route_flow_lookup_in_bucket(uint32_t > sip, > + uint32_t dip, void *bucket) > +{ > + odp_flow_entry_t *flow, *head; > + > + head = ((flow_bucket_t *)bucket)->next; > + for (flow = head; flow != NULL; flow = flow->next) { > + if ((flow->l3_src == sip) && (flow->l3_dst == dip)) > + return flow; > + } > + return NULL; > +} > + > +/** > + * Insert the flow into given hash bucket > + * > + * @param flow Which is to be inserted > + * @param bucket Target Hash Bucket > + * > + */ > +static inline void odp_route_flow_insert_in_bucket(odp_flow_entry_t > *flow, > + void > *bucket) > +{ > + odp_flow_entry_t *temp; > + flow_bucket_t *bkt = (flow_bucket_t *)bucket; > + > + if (!flow) { > + EXAMPLE_ERR("Invalid flow entry passed\n"); > + return; > + } > + > + LOCK(&bkt->lock); > + /*Check that entry already exist or not*/ > + temp = odp_route_flow_lookup_in_bucket(flow->l3_src, > flow->l3_dst, bkt); > + if (temp) { > + UNLOCK(&bkt->lock); > + return; > + } > + > + if (!bkt->next) { > + bkt->next = flow; > + } else { > + temp = bkt->next; > + flow->next = temp; > + bkt->next = flow; > + } > + UNLOCK(&bkt->lock); > +} > + > +/** 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 > + * > + * @param entries number of entries > + * > + * @return 0 if successful else -1 > + */ > +int create_fwd_db_entry(char *input, char **if_names, int if_count, int > entries); > + > +/** > + * Scan FWD DB entries and resolve output queue and source MAC address > + * > + * @param intf Interface name string > + * @param outq Output queue for packet transmit > + * @param mac MAC address of this interface > + */ > +void resolve_fwd_db(char *intf, 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_offload/odp_ipsec_offload_misc.h > b/example/ipsec_offload/odp_ipsec_offload_misc.h > new file mode 100644 > index 0000000..dbe6dc9 > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_misc.h > @@ -0,0 +1,384 @@ > +/* Copyright (c) 2017, 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 <odp.h> > +#include <odp/helper/eth.h> > +#include <odp/helper/ip.h> > +#include <odp/helper/ipsec.h> > + > +#ifndef TRUE > +#define TRUE 1 > +#endif > +#ifndef FALSE > +#define FALSE 0 > +#endif > + > +#define MAX_DB 1024 /**< maximum number of data base entries */ > +#define MAX_STRING 32 /**< maximum string length */ > +#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_AES 128 /**< AES cipher key length in bits */ > +#define KEY_BITS_SHA1_96 160 /**< SHA1_96 auth key length in bits */ > +#define KEY_BITS_SHA2_256 256 /**< SHA2_256 auth key length in bits */ > + > +/** > + * Number of buckets in hash table > + */ > +extern uint32_t bucket_count; > + > +#define LOCK(a) odp_spinlock_lock(a) > +#define UNLOCK(a) odp_spinlock_unlock(a) > +#define LOCK_INIT(a) odp_spinlock_init(a) > + > +/** > + * Hash calculation utility > + */ > +#define JHASH_GOLDEN_RATIO 0x9e3779b9 > +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) > +#define ODP_BJ3_MIX(a, b, c) \ > +{ \ > + a -= c; a ^= rot(c, 4); c += b; \ > + b -= a; b ^= rot(a, 6); a += c; \ > + c -= b; c ^= rot(b, 8); b += a; \ > + a -= c; a ^= rot(c, 16); c += b; \ > + b -= a; b ^= rot(a, 19); a += c; \ > + c -= b; c ^= rot(b, 4); b += a; \ > +} > + > +/** > + * Default Hash bucket number > + */ > +#define ODP_DEFAULT_BUCKET_COUNT 1024 > + > +/**< 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_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1)) > + > +/** 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)) > + > +/** > + * Actual entries > + */ > +typedef struct { > + odp_pktout_queue_t pktout; /**< queue handle*/ > + odph_ethaddr_t addr; /**< pktio MAC Address*/ > + odph_ethaddr_t next_hop_addr; /**< Next Hop MAC Address*/ > + odp_ipsec_sa_t sa; /**< IPSec sa handle*/ > +} odp_out_entry_t; > + > +/** > + * 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; > + if ((alg->u.cipher == ODP_CIPHER_ALG_AES128_CBC) && > + (KEY_BITS_AES == key_bits_in)) > + key->length = key_bits_in / 8; > + } else { > + if ((alg->u.auth == ODP_AUTH_ALG_MD5_96) && > + (KEY_BITS_MD5_96 == key_bits_in)) > + key->length = key_bits_in / 8; > + if ((alg->u.auth == ODP_AUTH_ALG_SHA1_96) && > + (KEY_BITS_SHA1_96 == key_bits_in)) > + key->length = key_bits_in / 8; > + if ((alg->u.auth == ODP_AUTH_ALG_SHA256_128) && > + (KEY_BITS_SHA2_256 == 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_compl_status_ok(odp_crypto_compl_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_offload/odp_ipsec_offload_sa_db.c > b/example/ipsec_offload/odp_ipsec_offload_sa_db.c > new file mode 100644 > index 0000000..c299daa > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.c > @@ -0,0 +1,361 @@ > +/* Copyright (c) 2017, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/* enable strtok */ > +#define _POSIX_C_SOURCE 200112L > + > +#include <stdlib.h> > +#include <string.h> > + > +#include <example_debug.h> > + > +#include <odp.h> > + > +#include <odp_ipsec_offload_sa_db.h> > + > +/** 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); > + > + sa_db = odp_shm_addr(shm); > + > + if (sa_db == NULL) { > + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); > + } > + 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); > + tun_db = odp_shm_addr(shm); > + > + if (!tun_db) { > + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); > + } > + memset(tun_db, 0, sizeof(*tun_db)); > +} > + > +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries) > +{ > + int pos = 0, count = 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; > + } else if (0 == strcmp(token, "aes")) { > + entry->alg.u.cipher = > + ODP_CIPHER_ALG_AES128_CBC; > + } else { > + entry->alg.u.cipher = > + ODP_CIPHER_ALG_NULL; > + } > + } else { > + if (0 == strcmp(token, "md5")) { > + entry->alg.u.auth = > + ODP_AUTH_ALG_MD5_96; > + } else if (0 == strcmp(token, "sha1")) { > + entry->alg.u.auth = > + ODP_AUTH_ALG_SHA1_96; > + } else if (0 == strcmp(token, "sha256")) { > + entry->alg.u.auth = > + ODP_AUTH_ALG_SHA256_128; > + } 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; > + count++; > + > + while (count < entries) { > + sa_db_entry_t *new_entry = &sa_db->array[sa_db->index]; > + > + /* Verify we have a good entry */ > + if (MAX_DB <= sa_db->index) > + return -1; > + > + new_entry->alg.cipher = entry->alg.cipher; > + new_entry->src_ip = entry->src_ip + count; > + new_entry->dst_ip = entry->dst_ip + count; > + new_entry->alg.u.cipher = entry->alg.u.cipher; > + new_entry->alg.u.auth = entry->alg.u.auth; > + new_entry->spi = entry->spi + count; > + new_entry->key = entry->key; > + new_entry->alg = entry->alg; > + /* Add route to the list */ > + sa_db->index++; > + new_entry->next = sa_db->list; > + sa_db->list = new_entry; > + count++; > + } > + > + free(local); > + return 0; > +} > + > +int create_tun_db_entry(char *input, int entries) > +{ > + int pos = 0, count = 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; > + count++; > + > + while (count < entries) { > + tun_db_entry_t *new_entry = &tun_db->array[tun_db->index]; > + > + /* Verify we have a good entry */ > + if (MAX_DB <= tun_db->index) > + return -1; > + > + new_entry->src_ip = entry->src_ip + count; > + new_entry->dst_ip = entry->dst_ip + count; > + new_entry->tun_src_ip = entry->tun_src_ip + count; > + new_entry->tun_dst_ip = entry->tun_dst_ip + count; > + /* Add route to the list */ > + tun_db->index++; > + new_entry->next = tun_db->list; > + tun_db->list = new_entry; > + count++; > + } > + > + 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 (ESP Only)\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; > + > + if (entry->alg.cipher) { > + printf(" %s %s %s %X %d ", > + "cipher", > + ipv4_addr_str(src_ip_str, entry->src_ip), > + ipv4_addr_str(dst_ip_str, entry->dst_ip), > + entry->spi, > + (int)entry->alg.u.cipher); > + } else { > + printf(" %s \t\t\t\t\t %X %d ", > + "auth", > + entry->spi, > + (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_offload/odp_ipsec_offload_sa_db.h > b/example/ipsec_offload/odp_ipsec_offload_sa_db.h > new file mode 100644 > index 0000000..02b49d4 > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.h > @@ -0,0 +1,126 @@ > +/* Copyright (c) 2017, 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 <odp_ipsec_offload_misc.h> > + > +/** > + * 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 */ > + odp_ipsec_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 > + * @param entries number of entries > + * > + * @return 0 if successful else -1 > + */ > +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries); > +/** > + * 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 > + * @param entries number of entries > + * > + * @return 0 if successful else -1 > + */ > +int create_tun_db_entry(char *input, int entries); > + > +/** > + * 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_offload/odp_ipsec_offload_sp_db.c > b/example/ipsec_offload/odp_ipsec_offload_sp_db.c > new file mode 100644 > index 0000000..9fcaaaa > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.c > @@ -0,0 +1,166 @@ > +/* Copyright (c) 2017, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/* enable strtok */ > +#define _POSIX_C_SOURCE 200112L > + > +#include <stdlib.h> > +#include <string.h> > + > +#include <example_debug.h> > + > +#include <odp.h> > + > +#include <odp_ipsec_offload_sp_db.h> > + > +/** 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); > + > + sp_db = odp_shm_addr(shm); > + > + if (sp_db == NULL) { > + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); > + } > + memset(sp_db, 0, sizeof(*sp_db)); > +} > + > +int create_sp_db_entry(char *input, int entries) > +{ > + int pos = 0, count = 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++; > + } > + > + /* 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; > + count++; > + while (count < entries) { > + sp_db_entry_t *new_entry = &sp_db->array[sp_db->index]; > + > + /* Verify we have a good entry */ > + if (MAX_DB <= sp_db->index) > + return -1; > + > + new_entry->src_subnet.addr = entry->src_subnet.addr + > count; > + new_entry->src_subnet.mask = entry->src_subnet.mask; > + new_entry->dst_subnet.addr = entry->dst_subnet.addr + > count; > + new_entry->dst_subnet.mask = entry->dst_subnet.mask; > + new_entry->input = entry->input; > + new_entry->esp = entry->esp; > + new_entry->ah = entry->ah; > + /* Add route to the list */ > + sp_db->index++; > + new_entry->next = sp_db->list; > + sp_db->list = new_entry; > + count++; > + } > + > + 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_offload/odp_ipsec_offload_sp_db.h > b/example/ipsec_offload/odp_ipsec_offload_sp_db.h > new file mode 100644 > index 0000000..bc6ba1a > --- /dev/null > +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.h > @@ -0,0 +1,72 @@ > +/* Copyright (c) 2017, 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 <odp_ipsec_offload_misc.h> > + > +/** > + * 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 string describing SP > + * > + * @param entries number of entries > + * > + * @return 0 if successful else -1 > + */ > +int create_sp_db_entry(char *input, int entries); > + > +/** > + * 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_offload/run_left b/example/ipsec_offload/run_ > left > new file mode 100644 > index 0000000..58986a2 > --- /dev/null > +++ b/example/ipsec_offload/run_left > @@ -0,0 +1,14 @@ > +#!/bin/bash > +# > + > +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \ > +-r 192.168.111.2/32:dpni.1:00.10.94.00.00.02 \ > +-r 192.168.222.2/32:dpni.2:00.00.00.00.00.1 \ > +-p 192.168.111.2:192.168.222.2:out:both \ > +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ > +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188e > e6aa0cf309a731649644c5dee92cbd9c2e \ > +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \ > +-p 192.168.222.2:192.168.111.2:in:both \ > +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ > +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188e > e6aa0cf309a731649644c5dee92cbd9c2e \ > +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 & > diff --git a/example/ipsec_offload/run_right b/example/ipsec_offload/run_ > right > new file mode 100644 > index 0000000..d49aa19 > --- /dev/null > +++ b/example/ipsec_offload/run_right > @@ -0,0 +1,14 @@ > +#!/bin/bash > +# > + > +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \ > +-r 192.168.111.2/32:dpni.1:00.00.00.00.00.2 \ > +-r 192.168.222.2/32:dpni.2:00.10.94.00.00.03 \ > +-p 192.168.111.2:192.168.222.2:in:both \ > +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ > +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188e > e6aa0cf309a731649644c5dee92cbd9c2e \ > +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \ > +-p 192.168.222.2:192.168.111.2:out:both \ > +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ > +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188e > e6aa0cf309a731649644c5dee92cbd9c2e \ > +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 & > diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 > index 620db04..03c006a 100644 > --- a/example/m4/configure.m4 > +++ b/example/m4/configure.m4 > @@ -14,6 +14,7 @@ AC_CONFIG_FILES([example/classifier/Makefile > example/generator/Makefile > example/hello/Makefile > example/ipsec/Makefile > + example/ipsec_offload/Makefile > example/l2fwd_simple/Makefile > example/l3fwd/Makefile > example/packet/Makefile > -- > 2.9.3 > >
Let's get some final changes, so that we can hopefully merge this patch On 22.02.2017 15:27, Nikhil Agarwal wrote: > Signed-off-by: Nikhil Agarwal <nikhil.agarwal@linaro.org> > --- [skipped] > + /* Read the source MAC address for this interface */ > + ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac)); > + if (ret < 0) { > + EXAMPLE_ABORT("Error: failed during MAC address get for %s\n", > + intf); > + } > + > + printf("Created pktio:%02" PRIu64 "\n", odp_pktio_to_u64(pktio)); This needs #include <inttypes.h> > + > + /* Resolve any routes using this interface for output */ > + resolve_fwd_db(intf, pktout, src_mac); > +} > + [skipped] > + > + } else if (ODP_EVENT_IPSEC_RESULT == odp_event_type(ev)) { > + odp_ipsec_op_result_t result; > + odp_ipsec_packet_result_t res; > + odph_ethhdr_t *eth; > + odp_packet_t out_pkt; > + > + result.pkt = &out_pkt; > + result.res = &res; > + > + if (odp_unlikely(odp_ipsec_result(&result, ev) < 0)) { > + EXAMPLE_DBG("Error Event\n"); > + odp_packet_free((odp_packet_t)ev); This should be odp_event_free() > + continue; > + } > + > + if (odp_unlikely(res.status.all)) { > + odp_packet_free((odp_packet_t)ev); I'm unsure here. event should be already freed by odp_isec_result(). So you should only free packets from result, not the event. > + continue; > + } > + > + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(out_pkt, NULL); > + > + if (ip->proto != IPPROTO_ESP) { > + rc = do_route_fwd_db(out_pkt); > + if (odp_unlikely(rc)) > + continue; > + } > + > + out_port = (odp_out_entry_t *)odp_packet_user_ptr(out_pkt); > + out_queue = (odp_pktout_queue_t)out_port->pktout; > + > + eth = (odph_ethhdr_t *)((void *)ip - sizeof(odph_ethhdr_t)); Void pointer arithmetics is an extension. Could you please change that to uint8_t *. > + eth->dst = out_port->next_hop_addr; > + eth->src = out_port->addr; > + eth->type = odp_cpu_to_be_16(0x800); > + > + if (odp_unlikely(odp_pktout_send(out_queue, &out_pkt, 1) < 0)) > + odp_packet_free(out_pkt); And here also just free packet, not an event. > + } else { > + EXAMPLE_DBG("Invalid Event\n"); > + odp_packet_free((odp_packet_t)ev); And here of course just call odp_event_free(), not packet_free! > + continue; > + } > + } > + [skipped] > +/** > + * Hash calculation utility > + */ > +#define JHASH_GOLDEN_RATIO 0x9e3779b9 > +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) > +#define ODP_BJ3_MIX(a, b, c) \ This is what Maxim wrote about. Could you please rename these two defines so that they don't pollute ODP_ namespace. > +{ \ > + a -= c; a ^= rot(c, 4); c += b; \ > + b -= a; b ^= rot(a, 6); a += c; \ > + c -= b; c ^= rot(b, 8); b += a; \ > + a -= c; a ^= rot(c, 16); c += b; \ > + b -= a; b ^= rot(a, 19); a += c; \ > + c -= b; c ^= rot(b, 4); b += a; \ > +} > + > +/** > + * Default Hash bucket number > + */ > +#define ODP_DEFAULT_BUCKET_COUNT 1024 [skipped] > +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; > + if ((alg->u.cipher == ODP_CIPHER_ALG_AES128_CBC) && ODP_CIPHER_ALG_AES_CBC? > + (KEY_BITS_AES == key_bits_in)) > + key->length = key_bits_in / 8; > + } else { > + if ((alg->u.auth == ODP_AUTH_ALG_MD5_96) && ODP_AUTH_ALG_MD5_HMAC > + (KEY_BITS_MD5_96 == key_bits_in)) > + key->length = key_bits_in / 8; > + if ((alg->u.auth == ODP_AUTH_ALG_SHA1_96) && ODP_AUTH_ALG_SHA1_HMAC > + (KEY_BITS_SHA1_96 == key_bits_in)) > + key->length = key_bits_in / 8; > + if ((alg->u.auth == ODP_AUTH_ALG_SHA256_128) && OD_AUTH_ALG_SHA256_HMAC > + (KEY_BITS_SHA2_256 == key_bits_in)) > + key->length = key_bits_in / 8; > + } > + [skipped] > + case 2: > + if (cipher) { > + if (0 == strcmp(token, "3des")) { > + entry->alg.u.cipher = > + ODP_CIPHER_ALG_3DES_CBC; > + } else if (0 == strcmp(token, "aes")) { > + entry->alg.u.cipher = > + ODP_CIPHER_ALG_AES128_CBC; ODP_CIPHER_ALG_AES_CBC > + } else { > + entry->alg.u.cipher = > + ODP_CIPHER_ALG_NULL; > + } > + } else { > + if (0 == strcmp(token, "md5")) { > + entry->alg.u.auth = > + ODP_AUTH_ALG_MD5_96; ODP_AUTH_ALG_MD5_HMAC > + } else if (0 == strcmp(token, "sha1")) { > + entry->alg.u.auth = > + ODP_AUTH_ALG_SHA1_96; ODP_AUTH_ALG_SHA1_HMAC > + } else if (0 == strcmp(token, "sha256")) { > + entry->alg.u.auth = > + ODP_AUTH_ALG_SHA256_128; ODP_AUTH_ALG_SHA256_HMAC > + } else { > + entry->alg.u.auth = ODP_AUTH_ALG_NULL; > + } > + } > + break; -- With best wishes Dmitry
diff --git a/example/Makefile.am b/example/Makefile.am index dfc07b6..24b9e52 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = classifier \ generator \ hello \ ipsec \ + ipsec_offload \ l2fwd_simple \ l3fwd \ packet \ diff --git a/example/ipsec_offload/.gitignore b/example/ipsec_offload/.gitignore new file mode 100644 index 0000000..2fc73aa --- /dev/null +++ b/example/ipsec_offload/.gitignore @@ -0,0 +1 @@ +odp_ipsec_offload diff --git a/example/ipsec_offload/Makefile.am b/example/ipsec_offload/Makefile.am new file mode 100644 index 0000000..a61b923 --- /dev/null +++ b/example/ipsec_offload/Makefile.am @@ -0,0 +1,19 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_ipsec_offload$(EXEEXT) +odp_ipsec_offload_LDFLAGS = $(AM_LDFLAGS) -static +odp_ipsec_offload_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example + +noinst_HEADERS = \ + $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_cache.h \ + $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_fwd_db.h \ + $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_misc.h \ + $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_sa_db.h \ + $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_sp_db.h \ + $(top_srcdir)/example/example_debug.h + +dist_odp_ipsec_offload_SOURCES = odp_ipsec_offload.c \ + odp_ipsec_offload_sa_db.c \ + odp_ipsec_offload_sp_db.c \ + odp_ipsec_offload_fwd_db.c \ + odp_ipsec_offload_cache.c diff --git a/example/ipsec_offload/odp_ipsec_offload.c b/example/ipsec_offload/odp_ipsec_offload.c new file mode 100644 index 0000000..4a494d0 --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload.c @@ -0,0 +1,871 @@ +/* Copyright (c) 2017, Linaro Limited + * Copyright (C) 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * @example odp_ipsec_offload.c ODP basic packet IO cross connect with IPsec + * test application + */ + +#define _DEFAULT_SOURCE +/* enable strtok */ +#define _POSIX_C_SOURCE 200112L +#include <stdlib.h> +#include <getopt.h> +#include <unistd.h> + +#include <example_debug.h> + +#include <odp_api.h> +#include <odp/helper/linux.h> +#include <odp/helper/eth.h> +#include <odp/helper/ip.h> +#include <odp/helper/icmp.h> +#include <odp/helper/udp.h> +#include <odp/helper/ipsec.h> + +#include <stdbool.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netpacket/packet.h> +#include <net/ethernet.h> +#include <arpa/inet.h> + +#include <odp_ipsec_offload_misc.h> +#include <odp_ipsec_offload_sa_db.h> +#include <odp_ipsec_offload_sp_db.h> +#include <odp_ipsec_offload_fwd_db.h> +#include <odp_ipsec_offload_cache.h> + +#define MAX_WORKERS 32 /**< maximum number of worker threads */ + +/** + * Parsed command line application arguments + */ +typedef struct { + int cpu_count; + int flows; + int if_count; /**< Number of interfaces to be used */ + char **if_names; /**< Array of pointers to interface names */ + char *if_str; /**< Storage for interface names */ + int queue_type; /**< Queue synchronization type*/ +} appl_args_t; +/** + * Grouping of both parsed CL args and thread specific args - alloc together + */ +typedef struct { + /** Application (parsed) arguments */ + appl_args_t appl; +} args_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); + +/** Global pointer to args */ +static args_t *args; + +/** + * 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) + +static odp_pool_t pkt_pool = ODP_POOL_INVALID; + +/** Synchronize threads before packet processing begins */ +static odp_barrier_t sync_barrier; + +/** + * 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; + +#define MAX_COMPL_QUEUES 32 +#define GET_THR_QUEUE_ID(x) ((odp_thread_id()-1) % (x)) + +/** Atomic queue IPSEC completion events */ +static odp_queue_t completionq[MAX_COMPL_QUEUES]; + +static int num_compl_queues; +static int num_workers; + + +/** + * Calculate hash value on given 2-tuple i.e. sip, dip + * + * @param ip_src Source IP Address + * @param ip_dst Destination IP Address + * + * @return Resultant hash value + */ +static inline uint64_t calculate_flow_hash(uint32_t ip_src, uint32_t ip_dst) +{ + uint64_t hash = 0; + + ip_dst += JHASH_GOLDEN_RATIO; + ODP_BJ3_MIX(ip_src, ip_dst, hash); + return hash; +} + +/** + * IPsec pre argument processing intialization + */ +static +void ipsec_init_pre(void) +{ + /* 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 + */ +static +void ipsec_init_post(void) +{ + sp_db_entry_t *entry; + int queue_id = 0; + + /* 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; + queue_id %= num_workers; + if (num_compl_queues < num_workers) + num_compl_queues++; + queue_id++; + 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, + entry->input, + completionq[queue_id - 1])) { + EXAMPLE_ABORT("Error: IPSec cache entry failed.\n"); + } + } else { + printf(" WARNING: SA not found for SP\n"); + dump_sp_db_entry(entry); + } + } +} + +/** + * Initialize interface + * + * Initialize ODP pktio and queues, query MAC address and update + * forwarding database. + * + * @param intf Interface name string + * @param queue_type Type of queue to configure. + */ +static void initialize_intf(char *intf, int queue_type) +{ + odp_pktio_t pktio; + odp_pktout_queue_t pktout; + int ret; + uint8_t src_mac[ODPH_ETHADDR_LEN]; + odp_pktio_param_t pktio_param; + odp_pktio_capability_t capa; + odp_pktin_queue_param_t pktin_param; + + odp_pktio_param_init(&pktio_param); + + 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, pkt_pool, &pktio_param); + if (ODP_PKTIO_INVALID == pktio) { + EXAMPLE_ABORT("Error: pktio create failed for %s\n", intf); + } + + odp_pktin_queue_param_init(&pktin_param); + + ret = odp_pktio_capability(pktio, &capa); + if (ret != 0) + EXAMPLE_ABORT("Error: Unable to get pktio capability %s\n", intf); + + pktin_param.queue_param.type = ODP_QUEUE_TYPE_SCHED; + pktin_param.queue_param.sched.sync = queue_type; + pktin_param.queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT; + pktin_param.num_queues = capa.max_input_queues; + + if (pktin_param.num_queues > 1) + pktin_param.hash_enable = 1; + + if (odp_pktin_queue_config(pktio, &pktin_param)) + EXAMPLE_ABORT("Error: pktin config failed for %s\n", intf); + + if (odp_pktout_queue_config(pktio, NULL)) + EXAMPLE_ABORT("Error: pktout config failed for %s\n", intf); + + if (odp_pktout_queue(pktio, &pktout, 1) != 1) + EXAMPLE_ABORT("Error: failed to get pktout queue for %s\n", intf); + + ret = odp_pktio_start(pktio); + if (ret) { + EXAMPLE_ABORT("Error: unable to start %s\n", intf); + } + + /* Read the source MAC address for this interface */ + ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac)); + if (ret < 0) { + EXAMPLE_ABORT("Error: failed during MAC address get for %s\n", + intf); + } + + printf("Created pktio:%02" PRIu64 "\n", odp_pktio_to_u64(pktio)); + + /* Resolve any routes using this interface for output */ + resolve_fwd_db(intf, pktout, src_mac); +} + +/** + * Packet Processing - Input verification + * + * @param pkt Packet to inspect + * + * @return PKT_CONTINUE if good, supported packet else PKT_DROP + */ +static pkt_disposition_e do_input_verify(odp_packet_t pkt) +{ + if (odp_unlikely(odp_packet_has_error(pkt))) { + odp_packet_free(pkt); + return PKT_DROP; + } + + if (!odp_packet_has_eth(pkt)) { + odp_packet_free(pkt); + return PKT_DROP; + } + + if (!odp_packet_has_ipv4(pkt)) { + odp_packet_free(pkt); + return PKT_DROP; + } + + return PKT_CONTINUE; +} + +/** + * Packet Processing - Route lookup in forwarding database + * + * @param pkt Packet to route + * + * @return PKT_CONTINUE if route found else PKT_DROP + */ +static +pkt_disposition_e do_route_fwd_db(odp_packet_t pkt) +{ + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); + fwd_db_entry_t *fwd_entry; + ipsec_cache_entry_t *ipsec_entry; + odp_ipsec_op_param_t params; + uint32_t sip, dip; + uint64_t hash; + odp_flow_entry_t *flow = NULL; + + if (ip->ttl > 1) { + ip->ttl -= 1; + if (ip->chksum >= odp_cpu_to_be_16(0xffff - 0x100)) + ip->chksum += odp_cpu_to_be_16(0x100) + 1; + else + ip->chksum += odp_cpu_to_be_16(0x100); + } else { + odp_packet_free(pkt); + return PKT_DROP; + } + + sip = odp_be_to_cpu_32(ip->src_addr); + dip = odp_be_to_cpu_32(ip->dst_addr); + + hash = calculate_flow_hash(sip, dip); + + flow = odp_route_flow_lookup_in_bucket(sip, dip, + &flow_table[hash & (bucket_count - 1)]); + if (flow) { +do_opt: + odp_packet_user_ptr_set(pkt, &flow->out_port); + if (flow->out_port.sa == ODP_IPSEC_SA_INVALID) + return PKT_CONTINUE; + + /* Initialize parameters block */ + params.sa = &flow->out_port.sa; + params.pkt = &pkt; + params.opt = NULL; + params.num_pkt = 1; + params.num_sa = 1; + params.num_opt = 1; + + /* Issue ipsec request */ + if (odp_unlikely(odp_ipsec_out_enq(¶ms) < 0)) { + EXAMPLE_DBG("Unable to out enqueue\n"); + odp_packet_free(pkt); + return PKT_DROP; + } + return PKT_POSTED; + } else { + /*Check into Routing table*/ + fwd_entry = find_fwd_db_entry(dip); + if (fwd_entry) { + /*Entry found. Updated in Flow table first.*/ + flow = calloc(1, sizeof(odp_flow_entry_t)); + if (!flow) { + EXAMPLE_ABORT("Failure to allocate memory"); + } + flow->l3_src = sip; + flow->l3_dst = dip; + flow->out_port.pktout = fwd_entry->pktout; + memcpy(flow->out_port.addr.addr, fwd_entry->src_mac, ODPH_ETHADDR_LEN); + memcpy(flow->out_port.next_hop_addr.addr, fwd_entry->dst_mac, ODPH_ETHADDR_LEN); + ipsec_entry = find_ipsec_cache_entry_out(sip, dip); + if (ipsec_entry) + flow->out_port.sa = ipsec_entry->sa; + else + flow->out_port.sa = ODP_IPSEC_SA_INVALID; + flow->next = NULL; + /*Insert new flow into flow cache table*/ + odp_route_flow_insert_in_bucket(flow, &flow_table[hash & (bucket_count - 1)]); + goto do_opt; + } else { + EXAMPLE_DBG("No flow match found. Packet is dropped.\n"); + odp_packet_free(pkt); + return PKT_DROP; + + } + } +} + + +/** + * Packet Processing - Input IPsec packet classification + * + * Verify the received packet has IPsec headers, + * if so issue ipsec request else skip. + * + * @param pkt Packet to classify + * + * @return PKT_CONTINUE if done else PKT_POSTED + */ +static +pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt) +{ + odp_ipsec_op_param_t params; + + if (!odp_packet_has_ipsec(pkt)) + return PKT_CONTINUE; + + /* Initialize parameters block */ + params.pkt = &pkt; + params.num_pkt = 1; + params.num_sa = 0; + params.num_opt = 0; + params.opt = NULL; + + /* Issue ipsec request */ + if (odp_unlikely(odp_ipsec_in_enq(¶ms) < 0)) { + EXAMPLE_DBG("Unable to in enqueue\n"); + odp_packet_free(pkt); + return PKT_DROP; + } + return PKT_POSTED; +} +/** + * Packet IO worker thread + * + * Loop calling odp_schedule to obtain packet from the two sources, + * and continue processing the packet. + * + * - Input interfaces (i.e. new work) + * - Per packet ipsec API completion queue + * + * @param arg Required by "odph_linux_pthread_create", unused + * + * @return NULL (should never return) + */ +static +void *pktio_thread(void *arg EXAMPLE_UNUSED) +{ + int thr; + odp_packet_t pkt; + odp_pktout_queue_t out_queue; + odp_out_entry_t *out_port; + odp_event_t ev = ODP_EVENT_INVALID; + thr = odp_thread_id(); + + printf("Pktio thread [%02i] starts\n", thr); + odp_barrier_wait(&sync_barrier); + + /* Loop packets */ + for (;;) { + pkt_disposition_e rc; + + ev = odp_schedule(NULL, ODP_SCHED_WAIT); + /* Use schedule to get event from any input queue */ + /* Determine new work versus completion */ + if (ODP_EVENT_PACKET == odp_event_type(ev)) { + pkt = odp_packet_from_event(ev); + + rc = do_input_verify(pkt); + if (odp_unlikely(rc)) + continue; + + rc = do_ipsec_in_classify(pkt); + if (rc) + continue; + + rc = do_route_fwd_db(pkt); + if (rc) + continue; + + out_port = (odp_out_entry_t *)odp_packet_user_ptr(pkt); + out_queue = (odp_pktout_queue_t)out_port->pktout; + + if (odp_unlikely(odp_pktout_send(out_queue, &pkt, 1) < 0)) + odp_packet_free(pkt); + + } else if (ODP_EVENT_IPSEC_RESULT == odp_event_type(ev)) { + odp_ipsec_op_result_t result; + odp_ipsec_packet_result_t res; + odph_ethhdr_t *eth; + odp_packet_t out_pkt; + + result.pkt = &out_pkt; + result.res = &res; + + if (odp_unlikely(odp_ipsec_result(&result, ev) < 0)) { + EXAMPLE_DBG("Error Event\n"); + odp_packet_free((odp_packet_t)ev); + continue; + } + + if (odp_unlikely(res.status.all)) { + odp_packet_free((odp_packet_t)ev); + continue; + } + + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(out_pkt, NULL); + + if (ip->proto != IPPROTO_ESP) { + rc = do_route_fwd_db(out_pkt); + if (odp_unlikely(rc)) + continue; + } + + out_port = (odp_out_entry_t *)odp_packet_user_ptr(out_pkt); + out_queue = (odp_pktout_queue_t)out_port->pktout; + + eth = (odph_ethhdr_t *)((void *)ip - sizeof(odph_ethhdr_t)); + eth->dst = out_port->next_hop_addr; + eth->src = out_port->addr; + eth->type = odp_cpu_to_be_16(0x800); + + if (odp_unlikely(odp_pktout_send(out_queue, &out_pkt, 1) < 0)) + odp_packet_free(out_pkt); + } else { + EXAMPLE_DBG("Invalid Event\n"); + odp_packet_free((odp_packet_t)ev); + continue; + } + } + + /* unreachable */ + return NULL; +} + +/** + * ODP ipsec proto example main function + */ +int +main(int argc, char *argv[]) +{ + odph_linux_pthread_t thread_tbl[MAX_WORKERS]; + int i; + odp_shm_t shm; + odp_cpumask_t cpumask; + char cpumaskstr[ODP_CPUMASK_STR_SIZE]; + odp_pool_param_t params; + odp_queue_param_t qparam; + odp_instance_t instance; + odph_linux_thr_params_t thr_params; + odp_ipsec_config_t config; + odp_ipsec_capability_t capa; + + /*Validate if user has passed only help option*/ + if (argc == 2) { + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { + usage(argv[0]); + exit(EXIT_SUCCESS); + } + } + + /* Initialize ODP before calling anything else */ + if (odp_init_global(&instance, NULL, NULL)) { + EXAMPLE_ABORT("Error: ODP global init failed.\n"); + } + /* Initialize this thread */ + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + EXAMPLE_ABORT("Error: ODP local init failed.\n"); + } + /* Reserve memory for arguments from shared memory */ + shm = odp_shm_reserve("shm_args", sizeof(args_t), + ODP_CACHE_LINE_SIZE, 0); + args = odp_shm_addr(shm); + + if (NULL == args) { + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); + } + memset(args, 0, sizeof(*args)); + + /* Must init our databases before parsing args */ + ipsec_init_pre(); + init_fwd_db(); + + /* Parse and store the application arguments */ + parse_args(argc, argv, &args->appl); + + /*Initialize route table for user given parameter*/ + odp_init_routing_table(); + + /* Print both system and application information */ + print_info(NO_PATH(argv[0]), &args->appl); + + if (odp_ipsec_capability(&capa)) + EXAMPLE_ABORT("Error: Capability not configured.\n"); + + odp_ipsec_config_init(&config); + + if (capa.op_mode_async && (capa.op_mode_async >= capa.op_mode_sync)) + config.op_mode = ODP_IPSEC_OP_MODE_ASYNC; + else + EXAMPLE_ABORT("Error: Sync mode not supported.\n"); + + if (odp_ipsec_config(&config)) + EXAMPLE_ABORT("Error: IPSec not configured.\n"); + + /* Default to system CPU count unless user specified */ + num_workers = MAX_WORKERS; + if (args->appl.cpu_count && args->appl.cpu_count <= MAX_WORKERS) + num_workers = args->appl.cpu_count; + + /* + * By default CPU #0 runs Linux kernel background tasks. + * Start mapping thread from CPU #1 + */ + num_workers = odp_cpumask_default_worker(&cpumask, num_workers); + (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr)); + + /* + * Create completion queues + */ + odp_queue_param_init(&qparam); + qparam.type = ODP_QUEUE_TYPE_SCHED; + qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; + qparam.sched.sync = args->appl.queue_type; + qparam.sched.group = ODP_SCHED_GROUP_ALL; + + for (i = 0; i < num_workers; i++) { + completionq[i] = odp_queue_create("completion", &qparam); + if (ODP_QUEUE_INVALID == completionq[i]) { + EXAMPLE_ABORT("Error: completion queue creation failed\n"); + } + } + 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(&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; + + pkt_pool = odp_pool_create("packet_pool", ¶ms); + + if (ODP_POOL_INVALID == pkt_pool) { + EXAMPLE_ABORT("Error: packet pool create failed.\n"); + } + + ipsec_init_post(); + + /* Initialize interfaces (which resolves FWD DB entries */ + for (i = 0; i < args->appl.if_count; i++) { + initialize_intf(args->appl.if_names[i], args->appl.queue_type); + } + + printf(" Configured queues SYNC type: [%s]\n", (args->appl.queue_type == 0)? + "PARALLEL":(args->appl.queue_type == 1)? + "ATOMIC":"ORDERED"); + 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; + + /* Create and initialize worker threads */ + odph_linux_pthread_create(thread_tbl, &cpumask, + &thr_params); + odph_linux_pthread_join(thread_tbl, num_workers); + + free(args->appl.if_names); + free(args->appl.if_str); + 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 struct option longopts[] = { + {"count", required_argument, NULL, 'c'}, + {"interface", required_argument, NULL, 'i'}, /* return 'i' */ + {"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' */ + {"flows", no_argument, NULL, 'f'}, /* return 'f' */ + {"queue type", required_argument, NULL, 'q'}, /* return 'q' */ + {"help", no_argument, NULL, 'h'}, /* return 'h' */ + {NULL, 0, NULL, 0} + }; + + appl_args->flows = 1; + appl_args->queue_type = ODP_SCHED_SYNC_ATOMIC; + + while (!rc) { + opt = getopt_long(argc, argv, "+c:i:h:r:p:a:e:t:s:q:f:", + longopts, &long_index); + if (opt < 0) + break; /* No more options */ + switch (opt) { + case 'f': + appl_args->flows = atoi(optarg); + if (appl_args->flows > 256) { + printf("Maximum acceptable value for -f is 256\n"); + rc = -1; + } + if (optind != 3) { + printf("-f must be the 1st argument of the command\n"); + rc = -1; + } + EXAMPLE_DBG("Bucket count = %d\n", bucket_count); + break; + case 'c': + appl_args->cpu_count = atoi(optarg); + break; + case 'i': + /* parse packet-io interface names */ + 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; token = strtok(NULL, ","), i++); + appl_args->if_count = i; + if (!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 *)); + if (!appl_args->if_names) { + EXAMPLE_ABORT("Memory allocation failure\n"); + } + /* Store the if names (reset names string) */ + strcpy(appl_args->if_str, optarg); + for (token = strtok(appl_args->if_str, ","), i = 0; + token; token = strtok(NULL, ","), i++) { + appl_args->if_names[i] = token; + } + break; + case 'r': + rc = create_fwd_db_entry(optarg, appl_args->if_names, + appl_args->if_count, appl_args->flows); + break; + case 'p': + rc = create_sp_db_entry(optarg, appl_args->flows); + break; + case 'a': + rc = create_sa_db_entry(optarg, FALSE, appl_args->flows); + break; + case 'e': + rc = create_sa_db_entry(optarg, TRUE, appl_args->flows); + break; + case 't': + rc = create_tun_db_entry(optarg, appl_args->flows); + break; + case 'q': + i = atoi(optarg); + if (i > ODP_SCHED_SYNC_ORDERED || i < ODP_SCHED_SYNC_PARALLEL) { + printf("Invalid queue type: setting default to atomic"); + break; + } + appl_args->queue_type = i; + 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; + + printf("\n" + "ODP system info\n" + "---------------\n" + "ODP API version: %s\n" + "CPU model: %s\n" + "CPU freq (hz): %"PRIu64"\n" + "Cache line size: %i\n" + "CPU count: %i\n" + "\n", + odp_version_api_str(), odp_cpu_model_str(), odp_cpu_hz_max(), + odp_sys_cache_line_size(), odp_cpu_count()); + printf("Running ODP application: \"%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" + "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:(md5|null):SPI:Key128\n" + " -t, --tun SrcIP:DstIP:TunSrcIP:TunDstIP\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" + " -t 192.168.111.2:192.168.222.2:192.168.150.1:192.168.150.2\n" + "\n" + "Optional OPTIONS\n" + " -f, --flows <number> routes count.\n" + " -c, --count <number> CPU count.\n" + " -q specify the queue type\n" + " 0: ODP_SCHED_SYNC_PARALLEL\n" + " 1: ODP_SCHED_SYNC_ATOMIC\n" + " 2: ODP_SCHED_SYNC_ORDERED\n" + " default is ODP_SCHED_SYNC_ATOMIC\n" + " -h, --help Display help and exit.\n" + "\n", NO_PATH(progname), NO_PATH(progname) + ); +} diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.c b/example/ipsec_offload/odp_ipsec_offload_cache.c new file mode 100644 index 0000000..5b6a036 --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_cache.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2017 NXP. All rights reserved. + */ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdlib.h> +#include <string.h> + +#include <example_debug.h> + +#include <odp.h> + +#include <odp/helper/ipsec.h> +#include <odp/helper/ip.h> + +#include <odp_ipsec_offload_cache.h> + +/** Global pointer to ipsec_cache db */ +ipsec_cache_t *ipsec_cache; + +#define IPDEFTTL 64 + +void init_ipsec_cache(void) +{ + odp_shm_t shm; + + shm = odp_shm_reserve("shm_ipsec_cache", + sizeof(ipsec_cache_t), + ODP_CACHE_LINE_SIZE, + 0); + + ipsec_cache = odp_shm_addr(shm); + + if (ipsec_cache == NULL) { + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); + } + memset(ipsec_cache, 0, sizeof(*ipsec_cache)); +} + +int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa, + sa_db_entry_t *auth_sa, + tun_db_entry_t *tun, + odp_bool_t in, + odp_queue_t completionq) +{ + odp_ipsec_sa_param_t sa_params; + ipsec_cache_entry_t *entry; + odp_ipsec_sa_t sa; + uint32_t src_ip, dst_ip; + + odp_ipsec_sa_param_init(&sa_params); + + /* 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 (!tun) { + printf("\n TRANSPORT MODE not supported"); + return -1; + } + + /* Setup parameters and call ipsec library to create sa */ + if (in) { + sa_params.dir = ODP_IPSEC_DIR_INBOUND; + sa_params.lookup_mode = ODP_IPSEC_LOOKUP_IN_UNIQUE_SA; + } else { + sa_params.dir = ODP_IPSEC_DIR_OUTBOUND; + sa_params.lookup_mode = ODP_IPSEC_LOOKUP_DISABLED; + } + + sa_params.dest_queue = completionq; + sa_params.mode = ODP_IPSEC_MODE_TUNNEL; + + /* Cipher */ + if (cipher_sa) { + sa_params.crypto.cipher_alg = cipher_sa->alg.u.cipher; + sa_params.crypto.cipher_key.data = cipher_sa->key.data; + sa_params.crypto.cipher_key.length = cipher_sa->key.length; + sa_params.spi = cipher_sa->spi; + } else { + sa_params.crypto.cipher_alg = ODP_CIPHER_ALG_NULL; + } + + /* Auth */ + if (auth_sa) { + sa_params.crypto.auth_alg = auth_sa->alg.u.auth; + sa_params.crypto.auth_key.data = auth_sa->key.data; + sa_params.crypto.auth_key.length = auth_sa->key.length; + } else { + sa_params.crypto.auth_alg = ODP_AUTH_ALG_NULL; + } + + src_ip = odp_cpu_to_be_32(tun->tun_src_ip); + dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip); + sa_params.tunnel.type = ODP_IPSEC_TUNNEL_IPV4; + sa_params.tunnel.ipv4.src_addr = &src_ip; + sa_params.tunnel.ipv4.dst_addr = &dst_ip; + sa_params.tunnel.ipv4.ttl = IPDEFTTL; + sa_params.tunnel.ipv4.dscp = 0; + sa_params.tunnel.ipv4.df = 1; + + sa = odp_ipsec_sa_create(&sa_params); + if (sa == ODP_IPSEC_SA_INVALID) + return -1; + + /* Copy selector IPs in cache entry*/ + if (cipher_sa) { + entry->src_ip = cipher_sa->src_ip; + entry->dst_ip = cipher_sa->dst_ip; + } else if (auth_sa) { + entry->src_ip = auth_sa->src_ip; + entry->dst_ip = auth_sa->dst_ip; + } + + /* Initialize state */ + entry->sa = sa; + + /* 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_out(uint32_t src_ip, + uint32_t dst_ip) +{ + 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; +} diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.h b/example/ipsec_offload/odp_ipsec_offload_cache.h new file mode 100644 index 0000000..65f4dda --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_cache.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2017, 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 <odp.h> +#include <odp/helper/ipsec.h> + +#include <odp_ipsec_offload_misc.h> +#include <odp_ipsec_offload_sa_db.h> + +/** + * IPsec cache data base entry + */ +typedef struct ipsec_cache_entry_s { + struct ipsec_cache_entry_s *next; /**< Next entry on list */ + uint32_t src_ip; /**< Source v4 address */ + uint32_t dst_ip; /**< Destination v4 address */ + odp_ipsec_sa_t sa; /**< IPSec sa handle */ +} 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 in Direction (input versus output) + * @param completionq Completion queue + * + * @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, + odp_bool_t in, + odp_queue_t completionq); + +/** + * Find a matching IPsec cache entry for output packet + * + * @param src_ip Source IPv4 address + * @param dst_ip Destination IPv4 address + * + * @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); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.c b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c new file mode 100644 index 0000000..860b3ee --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c @@ -0,0 +1,223 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#define _POSIX_C_SOURCE 200112L + +#include <stdlib.h> +#include <string.h> + +#include <example_debug.h> +#include <odp.h> + +#include <odp_ipsec_offload_fwd_db.h> + +/** + * Pointer to Flow cache table + */ +flow_bucket_t *flow_table; + +/** + * bucket count. It will be updated with user argument if provided + */ +uint32_t bucket_count = ODP_DEFAULT_BUCKET_COUNT; + +/** Global pointer to fwd db */ +fwd_db_t *fwd_db; + +void odp_init_routing_table(void) +{ + odp_shm_t hash_shm; + uint32_t i; + flow_bucket_t *bucket; + + /*Reserve memory for Routing hash table*/ + hash_shm = odp_shm_reserve("route_table", + sizeof(flow_bucket_t) * bucket_count, + ODP_CACHE_LINE_SIZE, 0); + flow_table = odp_shm_addr(hash_shm); + if (!flow_table) { + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); + } + /*Inialize Locks*/ + for (i = 0; i < bucket_count; i++) { + bucket = &flow_table[i]; + LOCK_INIT(&bucket->lock); + } + + memset(flow_table, 0, bucket_count * sizeof(flow_bucket_t)); +} + +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); + + fwd_db = odp_shm_addr(shm); + + if (fwd_db == NULL) { + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); + } + memset(fwd_db, 0, sizeof(*fwd_db)); +} + +int create_fwd_db_entry(char *input, char **if_names, int if_count, int entries) +{ + int pos = 0, i, match = 0, count = 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; + + count++; + + while (count < entries) { + fwd_db_entry_t *new_entry = &fwd_db->array[fwd_db->index]; + + /* Verify we haven't run out of space */ + if (MAX_DB <= fwd_db->index) + return -1; + + new_entry->subnet.addr = entry->subnet.addr + count; + new_entry->subnet.mask = entry->subnet.mask; + strncpy(new_entry->oif, entry->oif, OIF_LEN - 1); + new_entry->oif[OIF_LEN - 1] = 0; + new_entry->dst_mac[0] = entry->dst_mac[0]; + new_entry->dst_mac[1] = entry->dst_mac[1]; + new_entry->dst_mac[2] = entry->dst_mac[2]; + new_entry->dst_mac[3] = entry->dst_mac[3]; + new_entry->dst_mac[4] = entry->dst_mac[4]; + new_entry->dst_mac[5] = entry->dst_mac[5]; + + /* Add route to the list */ + fwd_db->index++; + new_entry->next = fwd_db->list; + fwd_db->list = new_entry; + count++; + } + + free(local); + return 0; +} + +void resolve_fwd_db(char *intf, 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->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_offload/odp_ipsec_offload_fwd_db.h b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h new file mode 100644 index 0000000..2f42596 --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h @@ -0,0 +1,198 @@ +/* Copyright (c) 2017, 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 <odp.h> +#include <odp/helper/eth.h> +#include <odp_ipsec_offload_misc.h> + +#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_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; + +/** + * Flow cache table entry + */ +typedef struct { + void *next; /**< Pointer to next flow in list*/ + uint32_t l3_src; /**< Source IP Address*/ + uint32_t l3_dst; /**< Destination IP Address*/ + odp_out_entry_t out_port; /**< Out interface of matching flow*/ +} odp_flow_entry_t; + +/** + * Flow cache table bucket + */ +typedef struct { + odp_spinlock_t lock; /**< Bucket lock*/ + odp_flow_entry_t *next; /**< Pointer to first flow entry in bucket*/ +} flow_bucket_t; + +/** +* Pointers to Flow cache tables +*/ +extern flow_bucket_t *flow_table; + +extern flow_bucket_t *ipsec_out_flow_table; + +extern flow_bucket_t *ipsec_in_flow_table; + +/** + * Number of buckets in hash table + */ +extern uint32_t bucket_count; + +/* + * Allocate and Initialize routing table with default Route entries. + * + */ +void odp_init_routing_table(void); + +/* + * Searches flow entry in given hash bucket according to given 5-tuple information + * + * @param sip Source IP Address + * @param dip Destination IP Address + * @param sport Source Port Number + * @param dport Destination Port Number + * @param proto IP protocol + * @param bucket Hash Bucket + * + * @return Matching flow entry + */ +static inline odp_flow_entry_t *odp_route_flow_lookup_in_bucket(uint32_t sip, + uint32_t dip, void *bucket) +{ + odp_flow_entry_t *flow, *head; + + head = ((flow_bucket_t *)bucket)->next; + for (flow = head; flow != NULL; flow = flow->next) { + if ((flow->l3_src == sip) && (flow->l3_dst == dip)) + return flow; + } + return NULL; +} + +/** + * Insert the flow into given hash bucket + * + * @param flow Which is to be inserted + * @param bucket Target Hash Bucket + * + */ +static inline void odp_route_flow_insert_in_bucket(odp_flow_entry_t *flow, + void *bucket) +{ + odp_flow_entry_t *temp; + flow_bucket_t *bkt = (flow_bucket_t *)bucket; + + if (!flow) { + EXAMPLE_ERR("Invalid flow entry passed\n"); + return; + } + + LOCK(&bkt->lock); + /*Check that entry already exist or not*/ + temp = odp_route_flow_lookup_in_bucket(flow->l3_src, flow->l3_dst, bkt); + if (temp) { + UNLOCK(&bkt->lock); + return; + } + + if (!bkt->next) { + bkt->next = flow; + } else { + temp = bkt->next; + flow->next = temp; + bkt->next = flow; + } + UNLOCK(&bkt->lock); +} + +/** 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 + * + * @param entries number of entries + * + * @return 0 if successful else -1 + */ +int create_fwd_db_entry(char *input, char **if_names, int if_count, int entries); + +/** + * Scan FWD DB entries and resolve output queue and source MAC address + * + * @param intf Interface name string + * @param outq Output queue for packet transmit + * @param mac MAC address of this interface + */ +void resolve_fwd_db(char *intf, 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_offload/odp_ipsec_offload_misc.h b/example/ipsec_offload/odp_ipsec_offload_misc.h new file mode 100644 index 0000000..dbe6dc9 --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_misc.h @@ -0,0 +1,384 @@ +/* Copyright (c) 2017, 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 <odp.h> +#include <odp/helper/eth.h> +#include <odp/helper/ip.h> +#include <odp/helper/ipsec.h> + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define MAX_DB 1024 /**< maximum number of data base entries */ +#define MAX_STRING 32 /**< maximum string length */ +#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_AES 128 /**< AES cipher key length in bits */ +#define KEY_BITS_SHA1_96 160 /**< SHA1_96 auth key length in bits */ +#define KEY_BITS_SHA2_256 256 /**< SHA2_256 auth key length in bits */ + +/** + * Number of buckets in hash table + */ +extern uint32_t bucket_count; + +#define LOCK(a) odp_spinlock_lock(a) +#define UNLOCK(a) odp_spinlock_unlock(a) +#define LOCK_INIT(a) odp_spinlock_init(a) + +/** + * Hash calculation utility + */ +#define JHASH_GOLDEN_RATIO 0x9e3779b9 +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) +#define ODP_BJ3_MIX(a, b, c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c, 16); c += b; \ + b -= a; b ^= rot(a, 19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/** + * Default Hash bucket number + */ +#define ODP_DEFAULT_BUCKET_COUNT 1024 + +/**< 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_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1)) + +/** 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)) + +/** + * Actual entries + */ +typedef struct { + odp_pktout_queue_t pktout; /**< queue handle*/ + odph_ethaddr_t addr; /**< pktio MAC Address*/ + odph_ethaddr_t next_hop_addr; /**< Next Hop MAC Address*/ + odp_ipsec_sa_t sa; /**< IPSec sa handle*/ +} odp_out_entry_t; + +/** + * 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; + if ((alg->u.cipher == ODP_CIPHER_ALG_AES128_CBC) && + (KEY_BITS_AES == key_bits_in)) + key->length = key_bits_in / 8; + } else { + if ((alg->u.auth == ODP_AUTH_ALG_MD5_96) && + (KEY_BITS_MD5_96 == key_bits_in)) + key->length = key_bits_in / 8; + if ((alg->u.auth == ODP_AUTH_ALG_SHA1_96) && + (KEY_BITS_SHA1_96 == key_bits_in)) + key->length = key_bits_in / 8; + if ((alg->u.auth == ODP_AUTH_ALG_SHA256_128) && + (KEY_BITS_SHA2_256 == 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_compl_status_ok(odp_crypto_compl_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_offload/odp_ipsec_offload_sa_db.c b/example/ipsec_offload/odp_ipsec_offload_sa_db.c new file mode 100644 index 0000000..c299daa --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.c @@ -0,0 +1,361 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#define _POSIX_C_SOURCE 200112L + +#include <stdlib.h> +#include <string.h> + +#include <example_debug.h> + +#include <odp.h> + +#include <odp_ipsec_offload_sa_db.h> + +/** 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); + + sa_db = odp_shm_addr(shm); + + if (sa_db == NULL) { + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); + } + 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); + tun_db = odp_shm_addr(shm); + + if (!tun_db) { + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); + } + memset(tun_db, 0, sizeof(*tun_db)); +} + +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries) +{ + int pos = 0, count = 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; + } else if (0 == strcmp(token, "aes")) { + entry->alg.u.cipher = + ODP_CIPHER_ALG_AES128_CBC; + } else { + entry->alg.u.cipher = + ODP_CIPHER_ALG_NULL; + } + } else { + if (0 == strcmp(token, "md5")) { + entry->alg.u.auth = + ODP_AUTH_ALG_MD5_96; + } else if (0 == strcmp(token, "sha1")) { + entry->alg.u.auth = + ODP_AUTH_ALG_SHA1_96; + } else if (0 == strcmp(token, "sha256")) { + entry->alg.u.auth = + ODP_AUTH_ALG_SHA256_128; + } 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; + count++; + + while (count < entries) { + sa_db_entry_t *new_entry = &sa_db->array[sa_db->index]; + + /* Verify we have a good entry */ + if (MAX_DB <= sa_db->index) + return -1; + + new_entry->alg.cipher = entry->alg.cipher; + new_entry->src_ip = entry->src_ip + count; + new_entry->dst_ip = entry->dst_ip + count; + new_entry->alg.u.cipher = entry->alg.u.cipher; + new_entry->alg.u.auth = entry->alg.u.auth; + new_entry->spi = entry->spi + count; + new_entry->key = entry->key; + new_entry->alg = entry->alg; + /* Add route to the list */ + sa_db->index++; + new_entry->next = sa_db->list; + sa_db->list = new_entry; + count++; + } + + free(local); + return 0; +} + +int create_tun_db_entry(char *input, int entries) +{ + int pos = 0, count = 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; + count++; + + while (count < entries) { + tun_db_entry_t *new_entry = &tun_db->array[tun_db->index]; + + /* Verify we have a good entry */ + if (MAX_DB <= tun_db->index) + return -1; + + new_entry->src_ip = entry->src_ip + count; + new_entry->dst_ip = entry->dst_ip + count; + new_entry->tun_src_ip = entry->tun_src_ip + count; + new_entry->tun_dst_ip = entry->tun_dst_ip + count; + /* Add route to the list */ + tun_db->index++; + new_entry->next = tun_db->list; + tun_db->list = new_entry; + count++; + } + + 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 (ESP Only)\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; + + if (entry->alg.cipher) { + printf(" %s %s %s %X %d ", + "cipher", + ipv4_addr_str(src_ip_str, entry->src_ip), + ipv4_addr_str(dst_ip_str, entry->dst_ip), + entry->spi, + (int)entry->alg.u.cipher); + } else { + printf(" %s \t\t\t\t\t %X %d ", + "auth", + entry->spi, + (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_offload/odp_ipsec_offload_sa_db.h b/example/ipsec_offload/odp_ipsec_offload_sa_db.h new file mode 100644 index 0000000..02b49d4 --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.h @@ -0,0 +1,126 @@ +/* Copyright (c) 2017, 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 <odp_ipsec_offload_misc.h> + +/** + * 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 */ + odp_ipsec_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 + * @param entries number of entries + * + * @return 0 if successful else -1 + */ +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries); +/** + * 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 + * @param entries number of entries + * + * @return 0 if successful else -1 + */ +int create_tun_db_entry(char *input, int entries); + +/** + * 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_offload/odp_ipsec_offload_sp_db.c b/example/ipsec_offload/odp_ipsec_offload_sp_db.c new file mode 100644 index 0000000..9fcaaaa --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.c @@ -0,0 +1,166 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* enable strtok */ +#define _POSIX_C_SOURCE 200112L + +#include <stdlib.h> +#include <string.h> + +#include <example_debug.h> + +#include <odp.h> + +#include <odp_ipsec_offload_sp_db.h> + +/** 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); + + sp_db = odp_shm_addr(shm); + + if (sp_db == NULL) { + EXAMPLE_ABORT("Error: shared mem alloc failed.\n"); + } + memset(sp_db, 0, sizeof(*sp_db)); +} + +int create_sp_db_entry(char *input, int entries) +{ + int pos = 0, count = 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++; + } + + /* 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; + count++; + while (count < entries) { + sp_db_entry_t *new_entry = &sp_db->array[sp_db->index]; + + /* Verify we have a good entry */ + if (MAX_DB <= sp_db->index) + return -1; + + new_entry->src_subnet.addr = entry->src_subnet.addr + count; + new_entry->src_subnet.mask = entry->src_subnet.mask; + new_entry->dst_subnet.addr = entry->dst_subnet.addr + count; + new_entry->dst_subnet.mask = entry->dst_subnet.mask; + new_entry->input = entry->input; + new_entry->esp = entry->esp; + new_entry->ah = entry->ah; + /* Add route to the list */ + sp_db->index++; + new_entry->next = sp_db->list; + sp_db->list = new_entry; + count++; + } + + 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_offload/odp_ipsec_offload_sp_db.h b/example/ipsec_offload/odp_ipsec_offload_sp_db.h new file mode 100644 index 0000000..bc6ba1a --- /dev/null +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2017, 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 <odp_ipsec_offload_misc.h> + +/** + * 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 string describing SP + * + * @param entries number of entries + * + * @return 0 if successful else -1 + */ +int create_sp_db_entry(char *input, int entries); + +/** + * 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_offload/run_left b/example/ipsec_offload/run_left new file mode 100644 index 0000000..58986a2 --- /dev/null +++ b/example/ipsec_offload/run_left @@ -0,0 +1,14 @@ +#!/bin/bash +# + +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \ +-r 192.168.111.2/32:dpni.1:00.10.94.00.00.02 \ +-r 192.168.222.2/32:dpni.2:00.00.00.00.00.1 \ +-p 192.168.111.2:192.168.222.2:out:both \ +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \ +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \ +-p 192.168.222.2:192.168.111.2:in:both \ +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \ +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 & diff --git a/example/ipsec_offload/run_right b/example/ipsec_offload/run_right new file mode 100644 index 0000000..d49aa19 --- /dev/null +++ b/example/ipsec_offload/run_right @@ -0,0 +1,14 @@ +#!/bin/bash +# + +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \ +-r 192.168.111.2/32:dpni.1:00.00.00.00.00.2 \ +-r 192.168.222.2/32:dpni.2:00.10.94.00.00.03 \ +-p 192.168.111.2:192.168.222.2:in:both \ +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \ +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \ +-p 192.168.222.2:192.168.111.2:out:both \ +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \ +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \ +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 & diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 index 620db04..03c006a 100644 --- a/example/m4/configure.m4 +++ b/example/m4/configure.m4 @@ -14,6 +14,7 @@ AC_CONFIG_FILES([example/classifier/Makefile example/generator/Makefile example/hello/Makefile example/ipsec/Makefile + example/ipsec_offload/Makefile example/l2fwd_simple/Makefile example/l3fwd/Makefile example/packet/Makefile
Signed-off-by: Nikhil Agarwal <nikhil.agarwal@linaro.org> --- example/Makefile.am | 1 + example/ipsec_offload/.gitignore | 1 + example/ipsec_offload/Makefile.am | 19 + example/ipsec_offload/odp_ipsec_offload.c | 871 +++++++++++++++++++++++ example/ipsec_offload/odp_ipsec_offload_cache.c | 148 ++++ example/ipsec_offload/odp_ipsec_offload_cache.h | 78 ++ example/ipsec_offload/odp_ipsec_offload_fwd_db.c | 223 ++++++ example/ipsec_offload/odp_ipsec_offload_fwd_db.h | 198 ++++++ example/ipsec_offload/odp_ipsec_offload_misc.h | 384 ++++++++++ example/ipsec_offload/odp_ipsec_offload_sa_db.c | 361 ++++++++++ example/ipsec_offload/odp_ipsec_offload_sa_db.h | 126 ++++ example/ipsec_offload/odp_ipsec_offload_sp_db.c | 166 +++++ example/ipsec_offload/odp_ipsec_offload_sp_db.h | 72 ++ example/ipsec_offload/run_left | 14 + example/ipsec_offload/run_right | 14 + example/m4/configure.m4 | 1 + 16 files changed, 2677 insertions(+) create mode 100644 example/ipsec_offload/.gitignore create mode 100644 example/ipsec_offload/Makefile.am create mode 100644 example/ipsec_offload/odp_ipsec_offload.c create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.c create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.h create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.c create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.h create mode 100644 example/ipsec_offload/odp_ipsec_offload_misc.h create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.c create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.h create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.c create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.h create mode 100644 example/ipsec_offload/run_left create mode 100644 example/ipsec_offload/run_right -- 2.9.3