Bill Fischofer(Bill-Fischofer-Linaro) replied on github web page: example/ipsec_offload/odp_ipsec_offload.c line 378 @@ -0,0 +1,855 @@ +/* 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 <inttypes.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; + BJ3_MIX(ip_src, ip_dst, hash); + return hash; +} + +/** + * IPsec pre argument processing initialization + */ +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 initialization + * + * 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; + 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) { + odp_ipsec_out_param_t params; + +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.opt = NULL; + params.num_sa = 1; + params.num_opt = 1; + + /* Issue ipsec request */ + if (odp_unlikely(odp_ipsec_out_enq(&pkt, 1, ¶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"); + return PKT_DROP; + } + 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; + } + } +}
Comment: Checkpatch doesn't like this and the `goto` is a bit ugly. Might a restructure along the following lines be simpler and cleaner? ``` if (!flow) { /*Check into Routing table*/ fwd_entry = find_fwd_db_entry(dip); if (!fwd_entry) { EXAMPLE_DBG("No flow match found. Packet is dropped.\n"); odp_packet_free(pkt); return PKT_DROP; } ... flow setup processing, fall though without needing a goto. } ...flow processing goes here ``` > Bill Fischofer(Bill-Fischofer-Linaro) wrote: > Drop the `odp_` prefix here. It's reserved for ODP APIs. >> Bill Fischofer(Bill-Fischofer-Linaro) wrote: >> Don't use the `odp_` prefix for application routines. It's not a good >> practice, especially in an example. https://github.com/Linaro/odp/pull/339#discussion_r157375293 updated_at 2017-12-17 18:09:27