From da41c7290e3cf1180de133a9213876037f6460a9 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 13 Dec 2017 19:09:40 +0300 Subject: [PATCH 1/5] linux-gen: loop: support multiple loop devices Add support for several loop devices "loop%d". Use "loop" instead of "loop0" for backwards compatibility. Signed-off-by: Dmitry Eremin-Solenikov --- .../include/odp_packet_io_internal.h | 1 + platform/linux-generic/pktio/loop.c | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 598b1ad500e..25e03718295 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -53,6 +53,7 @@ struct pktio_if_ops; typedef struct { odp_queue_t loopq; /**< loopback queue for "loop" device */ odp_bool_t promisc; /**< promiscuous mode state */ + uint8_t idx; /**< index of "loop" device */ } pkt_loop_t; #ifdef HAVE_PCAP diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index f887e1a2db8..698d363e4d6 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -22,6 +22,9 @@ #include #include #include +#include + +#define MAX_LOOP 16 /* MAC address for the "loop" interface */ static const char pktio_loop_mac[] = {0x02, 0xe9, 0x34, 0x80, 0x73, 0x01}; @@ -31,15 +34,26 @@ static int loopback_stats_reset(pktio_entry_t *pktio_entry); static int loopback_open(odp_pktio_t id, pktio_entry_t *pktio_entry, const char *devname, odp_pool_t pool ODP_UNUSED) { - if (strcmp(devname, "loop")) - return -1; - + long idx; char loopq_name[ODP_QUEUE_NAME_LEN]; + if (!strcmp(devname, "loop")) { + idx = 0; + } else if (!strncmp(devname, "loop", 4)) { + char *end; + + idx = strtol(devname + 4, &end, 10); + if (idx <= 0 || idx >= MAX_LOOP || *end) + return -1; + } else { + return -1; + } + snprintf(loopq_name, sizeof(loopq_name), "%" PRIu64 "-pktio_loopq", odp_pktio_to_u64(id)); pktio_entry->s.pkt_loop.loopq = odp_queue_create(loopq_name, NULL); + pktio_entry->s.pkt_loop.idx = idx; if (pktio_entry->s.pkt_loop.loopq == ODP_QUEUE_INVALID) return -1; @@ -213,6 +227,7 @@ static int loopback_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED, void *mac_addr) { memcpy(mac_addr, pktio_loop_mac, ETH_ALEN); + ((uint8_t *)mac_addr)[ETH_ALEN - 1] += pktio_entry->s.pkt_loop.idx; return ETH_ALEN; } From 0d0e81ffa49ada87cbe2b6fed4647c47c33c0ede Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 13 Dec 2017 19:11:26 +0300 Subject: [PATCH 2/5] example: ipsec: adapt to running on top of loop interfaces For quite a long time ipsec (well, crypto in fact) example lacked support for running on top of loopback interfaces, generating and verifying IPsec traffic on the same node. Historical loopback support was disabled, as it used plain queues instead of pktio support. Adapt ipsec example to use loop pktio interfaces. Signed-off-by: Dmitry Eremin-Solenikov --- example/ipsec/Makefile.am | 2 - example/ipsec/README | 3 +- example/ipsec/odp_ipsec.c | 87 +++----------------- example/ipsec/odp_ipsec_loop_db.c | 56 ------------- example/ipsec/odp_ipsec_loop_db.h | 128 ------------------------------ example/ipsec/odp_ipsec_stream.c | 46 +++++++---- example/ipsec/odp_ipsec_stream.h | 6 +- 7 files changed, 48 insertions(+), 280 deletions(-) delete mode 100644 example/ipsec/odp_ipsec_loop_db.c delete mode 100644 example/ipsec/odp_ipsec_loop_db.h diff --git a/example/ipsec/Makefile.am b/example/ipsec/Makefile.am index 46613065dce..85905ffa70a 100644 --- a/example/ipsec/Makefile.am +++ b/example/ipsec/Makefile.am @@ -19,12 +19,10 @@ odp_ipsec_SOURCES = odp_ipsec.c \ odp_ipsec_sa_db.c \ odp_ipsec_sp_db.c \ odp_ipsec_fwd_db.c \ - odp_ipsec_loop_db.c \ odp_ipsec_cache.c \ odp_ipsec_stream.c \ odp_ipsec_cache.h \ odp_ipsec_fwd_db.h \ - odp_ipsec_loop_db.h \ odp_ipsec_misc.h \ odp_ipsec_sa_db.h \ odp_ipsec_sp_db.h \ diff --git a/example/ipsec/README b/example/ipsec/README index 74f1d26e764..a8b741c7619 100644 --- a/example/ipsec/README +++ b/example/ipsec/README @@ -164,8 +164,7 @@ At VM2 console use tcpdump to observe IPsec packets : 6. Standalone Loopback Tests BASH batch files are now included to run several simple loopback tests that -do not require any packet IO. The scripts create internal "loopback" (not -real Linux loopback interfaces but simply ODP queues) as opposed to packet +do not require any packet IO. The scripts create internal "loopback" packet interfaces. Before running the example bash scripts add odp_ipsec to your PATH export PATH=":$PATH" diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c index 4015158ac8e..a69f9256482 100644 --- a/example/ipsec/odp_ipsec.c +++ b/example/ipsec/odp_ipsec.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -407,76 +406,20 @@ void ipsec_init_post(crypto_api_mode_e api_mode) } } -/** - * Initialize loopback - * - * Initialize ODP queues to create our own idea of loopbacks, which allow - * testing without physical interfaces. Interface name string will be of - * the format "loopX" where X is the decimal number of the interface. - * - * @param intf Loopback interface name string - */ -#if 0 /* Temporarely disable loopback mode. Needs packet output event queues */ static -void initialize_loop(char *intf) +int check_stream_db_out(const char *intf) { - int idx; - odp_queue_t outq_def; - odp_queue_t inq_def; - char queue_name[ODP_QUEUE_NAME_LEN]; - odp_queue_param_t qparam; - uint8_t *mac; - char mac_str[MAX_STRING]; - - /* Derive loopback interface index */ - idx = loop_if_index(intf); - if (idx < 0) { - EXAMPLE_ERR("Error: loopback \"%s\" invalid\n", intf); - exit(EXIT_FAILURE); - } + stream_db_entry_t *stream = NULL; - /* Create input queue */ - odp_queue_param_init(&qparam); - qparam.type = ODP_QUEUE_TYPE_SCHED; - qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; - qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; - qparam.sched.group = ODP_SCHED_GROUP_ALL; - snprintf(queue_name, sizeof(queue_name), "%i-loop_inq_def", idx); - queue_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; - - inq_def = queue_create(queue_name, &qparam); - if (ODP_QUEUE_INVALID == inq_def) { - EXAMPLE_ERR("Error: input queue creation failed for %s\n", - intf); - exit(EXIT_FAILURE); + /* For each stream look for input and output IPsec entries */ + for (stream = stream_db->list; NULL != stream; stream = stream->next) { + if (!strcmp(stream->output.intf, intf)) + return 1; } - /* Create output queue */ - snprintf(queue_name, sizeof(queue_name), "%i-loop_outq_def", idx); - queue_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; - outq_def = queue_create(queue_name, NULL); - if (ODP_QUEUE_INVALID == outq_def) { - EXAMPLE_ERR("Error: output queue creation failed for %s\n", - intf); - exit(EXIT_FAILURE); - } - - /* Initialize the loopback DB entry */ - create_loopback_db_entry(idx, inq_def, outq_def, pkt_pool); - mac = query_loopback_db_mac(idx); - - printf("Created loop:%02i, queue mode (ATOMIC queues)\n" - " default loop%02i-INPUT queue:%" PRIu64 "\n" - " default loop%02i-OUTPUT queue:%" PRIu64 "\n" - " source mac address %s\n", - idx, idx, odp_queue_to_u64(inq_def), idx, - odp_queue_to_u64(outq_def), - mac_addr_str(mac_str, mac)); - - /* Resolve any routes using this interface for output */ - resolve_fwd_db(intf, outq_def, mac); + return 0; } -#endif + /** * Initialize interface * @@ -499,7 +442,8 @@ void initialize_intf(char *intf) odp_pktio_param_init(&pktio_param); - if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) + if (getenv("ODP_IPSEC_USE_POLL_QUEUES") || + check_stream_db_out(intf)) pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE; else pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; @@ -1267,7 +1211,6 @@ main(int argc, char *argv[]) /* Must init our databases before parsing args */ ipsec_init_pre(); init_fwd_db(); - init_loopback_db(); init_stream_db(); /* Parse and store the application arguments */ @@ -1328,12 +1271,7 @@ main(int argc, char *argv[]) /* Initialize interfaces (which resolves FWD DB entries */ for (i = 0; i < args->appl.if_count; i++) { -#if 0 /* Temporarely disable loopback mode. Needs packet output event queues */ - if (!strncmp("loop", args->appl.if_names[i], strlen("loop"))) - initialize_loop(args->appl.if_names[i]); - else -#endif - initialize_intf(args->appl.if_names[i]); + initialize_intf(args->appl.if_names[i]); } /* If we have test streams build them before starting workers */ @@ -1377,9 +1315,6 @@ main(int argc, char *argv[]) shm = odp_shm_lookup("shm_fwd_db"); if (odp_shm_free(shm) != 0) EXAMPLE_ERR("Error: shm free shm_fwd_db failed\n"); - shm = odp_shm_lookup("loopback_db"); - if (odp_shm_free(shm) != 0) - EXAMPLE_ERR("Error: shm free loopback_db failed\n"); shm = odp_shm_lookup("shm_sa_db"); if (odp_shm_free(shm) != 0) EXAMPLE_ERR("Error: shm free shm_sa_db failed\n"); diff --git a/example/ipsec/odp_ipsec_loop_db.c b/example/ipsec/odp_ipsec_loop_db.c deleted file mode 100644 index 1d5e404eebb..00000000000 --- a/example/ipsec/odp_ipsec_loop_db.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2014, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include - -#include - -#include - -#include - -loopback_db_t *loopback_db; - -void init_loopback_db(void) -{ - int idx; - odp_shm_t shm; - - shm = odp_shm_reserve("loopback_db", - sizeof(loopback_db_t), - ODP_CACHE_LINE_SIZE, - 0); - - loopback_db = odp_shm_addr(shm); - - if (loopback_db == NULL) { - EXAMPLE_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(loopback_db, 0, sizeof(*loopback_db)); - - for (idx = 0; idx < MAX_LOOPBACK; idx++) { - loopback_db->intf[idx].inq_def = ODP_QUEUE_INVALID; - loopback_db->intf[idx].outq_def = ODP_QUEUE_INVALID; - } -} - -void create_loopback_db_entry(int idx, - odp_queue_t inq_def, - odp_queue_t outq_def, - odp_pool_t pkt_pool) -{ - loopback_db_entry_t *entry = &loopback_db->intf[idx]; - - /* Save queues */ - entry->inq_def = inq_def; - entry->outq_def = outq_def; - entry->pkt_pool = pkt_pool; - - /* Create dummy MAC address */ - memset(entry->mac, (0xF0 | idx), sizeof(entry->mac)); -} diff --git a/example/ipsec/odp_ipsec_loop_db.h b/example/ipsec/odp_ipsec_loop_db.h deleted file mode 100644 index 1f9ade6d3e9..00000000000 --- a/example/ipsec/odp_ipsec_loop_db.h +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2014, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_LOOP_DB_H_ -#define ODP_IPSEC_LOOP_DB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/** - * Loopback database entry structure - */ -typedef struct loopback_db_entry_s { - odp_queue_t inq_def; - odp_queue_t outq_def; - odp_pool_t pkt_pool; - uint8_t mac[ODPH_ETHADDR_LEN]; -} loopback_db_entry_t; - -typedef struct loopback_db_s { - loopback_db_entry_t intf[MAX_LOOPBACK]; -} loopback_db_t; - -extern loopback_db_t *loopback_db; - -/** Initialize loopback database global control structure */ -void init_loopback_db(void); - -/** - * Create loopback DB entry for an interface - * - * Loopback interfaces are specified from command line with - * an index 0-9. - * - * @param idx Index of interface in database - * @param inq_def Input queue - * @param outq_def Output queue - * @param pkt_pool Pool to create packets from - */ -void create_loopback_db_entry(int idx, - odp_queue_t inq_def, - odp_queue_t outq_def, - odp_pool_t pkt_pool); - -/** - * Parse loop interface index - * - * @param b Pointer to buffer to parse - * - * @return interface index (0 to (MAX_LOOPBACK - 1)) else -1 - */ -static inline -int loop_if_index(char *b) -{ - int ret; - int idx; - - /* Derive loopback interface index */ - ret = sscanf(b, "loop%d", &idx); - if ((1 != ret) || (idx < 0) || (idx >= MAX_LOOPBACK)) - return -1; - return idx; -} - -/** - * Query loopback DB entry MAC address - * - * @param idx Loopback DB index of the interface - * - * @return MAC address pointer - */ -static inline -uint8_t *query_loopback_db_mac(int idx) -{ - return loopback_db->intf[idx].mac; -} - -/** - * Query loopback DB entry input queue - * - * @param idx Loopback DB index of the interface - * - * @return ODP queue - */ -static inline -odp_queue_t query_loopback_db_inq(int idx) -{ - return loopback_db->intf[idx].inq_def; -} - -/** - * Query loopback DB entry output queue - * - * @param idx Loopback DB index of the interface - * - * @return ODP queue - */ -static inline -odp_queue_t query_loopback_db_outq(int idx) -{ - return loopback_db->intf[idx].outq_def; -} - -/** - * Query loopback DB entry packet pool - * - * @param idx Loopback DB index of the interface - * - * @return ODP buffer pool - */ -static inline -odp_pool_t query_loopback_db_pkt_pool(int idx) -{ - return loopback_db->intf[idx].pkt_pool; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/example/ipsec/odp_ipsec_stream.c b/example/ipsec/odp_ipsec_stream.c index bc5d572f01e..c287282e897 100644 --- a/example/ipsec/odp_ipsec_stream.c +++ b/example/ipsec/odp_ipsec_stream.c @@ -24,7 +24,6 @@ #include #include -#include #define STREAM_MAGIC 0xBABE01234567CAFE @@ -94,15 +93,10 @@ int create_stream_db_entry(char *input) parse_ipv4_string(token, &entry->dst_ip, NULL); break; case 2: - entry->input.loop = loop_if_index(token); - if (entry->input.loop < 0) { - EXAMPLE_ERR("Error: stream must have input" - " loop\n"); - exit(EXIT_FAILURE); - } + entry->input.intf = strdup(token); break; case 3: - entry->output.loop = loop_if_index(token); + entry->output.intf = strdup(token); break; case 4: entry->count = atoi(token); @@ -157,11 +151,15 @@ void resolve_stream_db(void) NULL); stream->input.entry = entry; + stream->input.pktio = odp_pktio_lookup(stream->input.intf); + /* Lookup output entry */ entry = find_ipsec_cache_entry_out(stream->src_ip, stream->dst_ip, 0); stream->output.entry = entry; + + stream->output.pktio = odp_pktio_lookup(stream->output.intf); } } @@ -556,8 +554,25 @@ int create_stream_db_inputs(void) /* For each stream create corresponding input packets */ for (stream = stream_db->list; NULL != stream; stream = stream->next) { int count; - uint8_t *dmac = query_loopback_db_mac(stream->input.loop); - odp_queue_t queue = query_loopback_db_inq(stream->input.loop); + int ret; + uint8_t dmac[ODPH_ETHADDR_LEN]; + odp_pktout_queue_t queue; + + ret = odp_pktio_mac_addr(stream->input.pktio, + dmac, sizeof(dmac)); + if (ret <= 0) { + EXAMPLE_ERR("Error: failed during MAC address get " + "for %s\n", + stream->input.intf); + continue; + } + + ret = odp_pktout_queue(stream->input.pktio, &queue, 1); + if (ret < 1) { + EXAMPLE_ERR("Error: failed to get outqueue for %s\n", + stream->input.intf); + continue; + } for (count = stream->count; count > 0; count--) { odp_packet_t pkt; @@ -568,7 +583,7 @@ int create_stream_db_inputs(void) break; } stream->created++; - if (odp_queue_enq(queue, odp_packet_to_event(pkt))) { + if (odp_pktout_send(queue, &pkt, 1) != 1) { odp_packet_free(pkt); printf("Queue enqueue failed\n"); break; @@ -594,13 +609,16 @@ odp_bool_t verify_stream_db_outputs(void) for (stream = stream_db->list; NULL != stream; stream = stream->next) { int idx; int count; + int ret; odp_queue_t queue; odp_event_t ev_tbl[LOOP_DEQ_COUNT]; - queue = query_loopback_db_outq(stream->output.loop); - - if (ODP_QUEUE_INVALID == queue) + ret = odp_pktin_event_queue(stream->output.pktio, &queue, 1); + if (ret < 1) { + EXAMPLE_ERR("Error: failed to get inqueue for %s\n", + stream->output.intf); continue; + } for (;;) { if (env) { diff --git a/example/ipsec/odp_ipsec_stream.h b/example/ipsec/odp_ipsec_stream.h index 6f6f7dff48b..4d047360a12 100644 --- a/example/ipsec/odp_ipsec_stream.h +++ b/example/ipsec/odp_ipsec_stream.h @@ -28,13 +28,15 @@ typedef struct stream_db_entry_s { uint32_t created; /**< Number successfully created */ uint32_t verified; /**< Number successfully verified */ struct { - int loop; /**< Input loop interface index */ + const char *intf; /**< Input interface name */ + odp_pktio_t pktio; /**< Input PktI/O interface */ uint32_t ah_seq; /**< AH sequence number if present */ uint32_t esp_seq; /**< ESP sequence number if present */ ipsec_cache_entry_t *entry; /**< IPsec to apply on input */ } input; struct { - int loop; /**< Output loop interface index */ + const char *intf; /**< Output interface name */ + odp_pktio_t pktio; /**< Output PktI/O interface */ ipsec_cache_entry_t *entry; /**t IPsec to verify on output */ } output; } stream_db_entry_t; From fde27d29be7897e6f3661e1d403201ca15e00787 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 13 Dec 2017 21:50:11 +0300 Subject: [PATCH 3/5] example: adapt ipsec example to use IPsec API Adapt old (crypto-only) IPsec example to use IPsec API. Signed-off-by: Dmitry Eremin-Solenikov --- example/Makefile.am | 1 + example/ipsec/odp_ipsec.c | 2 +- example/ipsec/odp_ipsec_fwd_db.c | 4 +- example/ipsec/odp_ipsec_fwd_db.h | 5 +- example/ipsec_api/.gitignore | 1 + example/ipsec_api/Makefile.am | 29 + example/ipsec_api/odp_ipsec.c | 1248 +++++++++++++++++ example/ipsec_api/odp_ipsec_cache.c | 180 +++ example/ipsec_api/odp_ipsec_cache.h | 112 ++ example/ipsec_api/odp_ipsec_fwd_db.c | 1 + example/ipsec_api/odp_ipsec_fwd_db.h | 1 + example/ipsec_api/odp_ipsec_misc.h | 1 + example/ipsec_api/odp_ipsec_run_ah_in.sh | 12 + example/ipsec_api/odp_ipsec_run_ah_out.sh | 12 + example/ipsec_api/odp_ipsec_run_ah_tun_in.sh | 13 + example/ipsec_api/odp_ipsec_run_ah_tun_out.sh | 13 + example/ipsec_api/odp_ipsec_run_esp_in.sh | 13 + example/ipsec_api/odp_ipsec_run_esp_out.sh | 13 + example/ipsec_api/odp_ipsec_run_esp_tun_in.sh | 14 + .../ipsec_api/odp_ipsec_run_esp_tun_out.sh | 13 + example/ipsec_api/odp_ipsec_run_live.sh | 17 + example/ipsec_api/odp_ipsec_run_router.sh | 9 + example/ipsec_api/odp_ipsec_run_simple.sh | 10 + example/ipsec_api/odp_ipsec_sa_db.c | 1 + example/ipsec_api/odp_ipsec_sa_db.h | 1 + example/ipsec_api/odp_ipsec_sp_db.c | 1 + example/ipsec_api/odp_ipsec_sp_db.h | 1 + example/ipsec_api/odp_ipsec_stream.c | 1 + example/ipsec_api/odp_ipsec_stream.h | 1 + example/m4/configure.m4 | 1 + 30 files changed, 1728 insertions(+), 3 deletions(-) create mode 100644 example/ipsec_api/.gitignore create mode 100644 example/ipsec_api/Makefile.am create mode 100644 example/ipsec_api/odp_ipsec.c create mode 100644 example/ipsec_api/odp_ipsec_cache.c create mode 100644 example/ipsec_api/odp_ipsec_cache.h create mode 120000 example/ipsec_api/odp_ipsec_fwd_db.c create mode 120000 example/ipsec_api/odp_ipsec_fwd_db.h create mode 120000 example/ipsec_api/odp_ipsec_misc.h create mode 100755 example/ipsec_api/odp_ipsec_run_ah_in.sh create mode 100755 example/ipsec_api/odp_ipsec_run_ah_out.sh create mode 100755 example/ipsec_api/odp_ipsec_run_ah_tun_in.sh create mode 100755 example/ipsec_api/odp_ipsec_run_ah_tun_out.sh create mode 100755 example/ipsec_api/odp_ipsec_run_esp_in.sh create mode 100755 example/ipsec_api/odp_ipsec_run_esp_out.sh create mode 100755 example/ipsec_api/odp_ipsec_run_esp_tun_in.sh create mode 100755 example/ipsec_api/odp_ipsec_run_esp_tun_out.sh create mode 100755 example/ipsec_api/odp_ipsec_run_live.sh create mode 100755 example/ipsec_api/odp_ipsec_run_router.sh create mode 100755 example/ipsec_api/odp_ipsec_run_simple.sh create mode 120000 example/ipsec_api/odp_ipsec_sa_db.c create mode 120000 example/ipsec_api/odp_ipsec_sa_db.h create mode 120000 example/ipsec_api/odp_ipsec_sp_db.c create mode 120000 example/ipsec_api/odp_ipsec_sp_db.h create mode 120000 example/ipsec_api/odp_ipsec_stream.c create mode 120000 example/ipsec_api/odp_ipsec_stream.h diff --git a/example/Makefile.am b/example/Makefile.am index 695e029c95c..0fc6c2ecb5a 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = classifier \ generator \ hello \ ipsec \ + ipsec_api \ ipfragreass \ l2fwd_simple \ l3fwd \ diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c index a69f9256482..001f520841f 100644 --- a/example/ipsec/odp_ipsec.c +++ b/example/ipsec/odp_ipsec.c @@ -502,7 +502,7 @@ void initialize_intf(char *intf) mac_addr_str(src_mac_str, src_mac)); /* Resolve any routes using this interface for output */ - resolve_fwd_db(intf, pktout, src_mac); + resolve_fwd_db(intf, pktio, pktout, src_mac); } /** diff --git a/example/ipsec/odp_ipsec_fwd_db.c b/example/ipsec/odp_ipsec_fwd_db.c index e1f6384619e..d52c3490d4c 100644 --- a/example/ipsec/odp_ipsec_fwd_db.c +++ b/example/ipsec/odp_ipsec_fwd_db.c @@ -119,7 +119,8 @@ int create_fwd_db_entry(char *input, char **if_names, int if_count) return 0; } -void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac) +void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout, + uint8_t *mac) { fwd_db_entry_t *entry; @@ -128,6 +129,7 @@ void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac) if (strcmp(intf, entry->oif)) continue; + entry->pktio = pktio; entry->pktout = pktout; memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN); } diff --git a/example/ipsec/odp_ipsec_fwd_db.h b/example/ipsec/odp_ipsec_fwd_db.h index 152bdfbde3c..771f58e0d0d 100644 --- a/example/ipsec/odp_ipsec_fwd_db.h +++ b/example/ipsec/odp_ipsec_fwd_db.h @@ -22,6 +22,7 @@ extern "C" { typedef struct fwd_db_entry_s { struct fwd_db_entry_s *next; /**< Next entry on list */ char oif[OIF_LEN]; /**< Output interface name */ + odp_pktio_t pktio; /**< Output PktI/O interface */ odp_pktout_queue_t pktout; /**< Output transmit queue */ uint8_t src_mac[ODPH_ETHADDR_LEN]; /**< Output source MAC */ uint8_t dst_mac[ODPH_ETHADDR_LEN]; /**< Output destination MAC */ @@ -62,10 +63,12 @@ int create_fwd_db_entry(char *input, char **if_names, int if_count); * Scan FWD DB entries and resolve output queue and source MAC address * * @param intf Interface name string + * @param pktio Output packet interface * @param outq Output queue for packet transmit * @param mac MAC address of this interface */ -void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac); +void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout, + uint8_t *mac); /** * Display one fowarding database entry diff --git a/example/ipsec_api/.gitignore b/example/ipsec_api/.gitignore new file mode 100644 index 00000000000..5b410d31b3f --- /dev/null +++ b/example/ipsec_api/.gitignore @@ -0,0 +1 @@ +odp_ipsec diff --git a/example/ipsec_api/Makefile.am b/example/ipsec_api/Makefile.am new file mode 100644 index 00000000000..847326fc06a --- /dev/null +++ b/example/ipsec_api/Makefile.am @@ -0,0 +1,29 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_ipsec + +dist_bin_SCRIPTS = \ + $(srcdir)/odp_ipsec_run_ah_in.sh \ + $(srcdir)/odp_ipsec_run_ah_out.sh \ + $(srcdir)/odp_ipsec_run_ah_tun_in.sh \ + $(srcdir)/odp_ipsec_run_ah_tun_out.sh \ + $(srcdir)/odp_ipsec_run_esp_in.sh \ + $(srcdir)/odp_ipsec_run_esp_out.sh \ + $(srcdir)/odp_ipsec_run_esp_tun_in.sh \ + $(srcdir)/odp_ipsec_run_esp_tun_out.sh \ + $(srcdir)/odp_ipsec_run_live.sh \ + $(srcdir)/odp_ipsec_run_router.sh \ + $(srcdir)/odp_ipsec_run_simple.sh + +odp_ipsec_SOURCES = odp_ipsec.c \ + odp_ipsec_sa_db.c \ + odp_ipsec_sa_db.h \ + odp_ipsec_sp_db.c \ + odp_ipsec_sp_db.h \ + odp_ipsec_fwd_db.c \ + odp_ipsec_fwd_db.h \ + odp_ipsec_cache.c \ + odp_ipsec_cache.h \ + odp_ipsec_stream.c \ + odp_ipsec_stream.h \ + odp_ipsec_misc.h diff --git a/example/ipsec_api/odp_ipsec.c b/example/ipsec_api/odp_ipsec.c new file mode 100644 index 00000000000..6e7350c96d9 --- /dev/null +++ b/example/ipsec_api/odp_ipsec.c @@ -0,0 +1,1248 @@ +/* Copyright (c) 2013, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * @example odp_example_ipsec.c ODP basic packet IO cross connect with IPsec test application + */ + +/* enable strtok */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAX_WORKERS 32 /**< maximum number of worker threads */ + +/** + * Parsed command line application arguments + */ +typedef struct { + int cpu_count; + int if_count; /**< Number of interfaces to be used */ + char **if_names; /**< Array of pointers to interface names */ + odp_ipsec_op_mode_t mode; /**< IPsec operation mode */ + odp_pool_t pool; /**< Buffer pool for packet IO */ + char *if_str; /**< Storage for interface names */ + odp_bool_t lookup; +} 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; + +/** ORDERED queue (eventually) for per packet crypto API completion events */ +static odp_queue_t completionq = ODP_QUEUE_INVALID; + +/** Synchronize threads before packet processing begins */ +static odp_barrier_t sync_barrier; + +/** + * Packet processing states/steps + */ +typedef enum { + PKT_STATE_INPUT_VERIFY, /**< Verify IPv4 and ETH */ + PKT_STATE_IPSEC_IN_CLASSIFY, /**< Initiate input IPsec */ + PKT_STATE_ROUTE_LOOKUP, /**< Use DST IP to find output IF */ + PKT_STATE_IPSEC_OUT_CLASSIFY, /**< Intiate output IPsec */ + PKT_STATE_TRANSMIT, /**< Send packet to output IF queue */ +} pkt_state_e; + +/** + * Packet processing result codes + */ +typedef enum { + PKT_CONTINUE, /**< No events posted, keep processing */ + PKT_POSTED, /**< Event posted, stop processing */ + PKT_DROP, /**< Reason to drop detected, stop processing */ + PKT_DONE /**< Finished with packet, stop processing */ +} pkt_disposition_e; + +/** + * Per packet processing context + */ +typedef struct { + odp_buffer_t buffer; /**< Buffer for context */ + pkt_state_e state; /**< Next processing step */ + odp_pktout_queue_t pktout; /**< Packet output queue */ + odp_pktio_t pktio; /**< Packet I/O */ + odph_ethhdr_t eth; /**< L2 header */ +} pkt_ctx_t; + +#define SHM_CTX_POOL_BUF_SIZE (sizeof(pkt_ctx_t)) +#define SHM_CTX_POOL_BUF_COUNT (SHM_PKT_POOL_BUF_COUNT) +#define SHM_CTX_POOL_SIZE (SHM_CTX_POOL_BUF_COUNT * SHM_CTX_POOL_BUF_SIZE) + +static odp_pool_t ctx_pool = ODP_POOL_INVALID; + +/** + * Allocate per packet processing context and associate it with + * packet buffer + * + * @param pkt Packet + * + * @return pointer to context area + */ +static +pkt_ctx_t *alloc_pkt_ctx(odp_packet_t pkt) +{ + odp_buffer_t ctx_buf = odp_buffer_alloc(ctx_pool); + pkt_ctx_t *ctx; + + if (odp_unlikely(ODP_BUFFER_INVALID == ctx_buf)) + return NULL; + + ctx = odp_buffer_addr(ctx_buf); + memset(ctx, 0, sizeof(*ctx)); + ctx->buffer = ctx_buf; + odp_packet_user_ptr_set(pkt, ctx); + + return ctx; +} + +/** + * Release per packet resources + * + * @param ctx Packet context + */ +static +void free_pkt_ctx(pkt_ctx_t *ctx) +{ + odp_buffer_free(ctx->buffer); +} + +/** + * Example supports either polling queues or using odp_schedule + */ +typedef odp_queue_t (*queue_create_func_t) + (const char *, const odp_queue_param_t *); +typedef odp_event_t (*schedule_func_t) (odp_queue_t *); + +static queue_create_func_t queue_create; +static schedule_func_t schedule; + +#define MAX_POLL_QUEUES 256 + +static odp_queue_t poll_queues[MAX_POLL_QUEUES]; +static int num_polled_queues; + +/** + * odp_queue_create wrapper to enable polling versus scheduling + */ +static +odp_queue_t polled_odp_queue_create(const char *name, + const odp_queue_param_t *param) +{ + odp_queue_t my_queue; + odp_queue_param_t qp; + odp_queue_type_t type; + + odp_queue_param_init(&qp); + if (param) + memcpy(&qp, param, sizeof(odp_queue_param_t)); + + type = qp.type; + + if (ODP_QUEUE_TYPE_SCHED == type) { + printf("%s: change %s to PLAIN\n", __func__, name); + qp.type = ODP_QUEUE_TYPE_PLAIN; + } + + my_queue = odp_queue_create(name, &qp); + + if (ODP_QUEUE_TYPE_SCHED == type) { + poll_queues[num_polled_queues++] = my_queue; + printf("%s: adding %" PRIu64 "\n", __func__, + odp_queue_to_u64(my_queue)); + } + + return my_queue; +} + +static inline +odp_event_t odp_schedule_cb(odp_queue_t *from) +{ + return odp_schedule(from, ODP_SCHED_WAIT); +} + +/** + * odp_schedule replacement to poll queues versus using ODP scheduler + */ +static +odp_event_t polled_odp_schedule_cb(odp_queue_t *from) +{ + int idx = 0; + + while (1) { + if (idx >= num_polled_queues) + idx = 0; + + odp_queue_t queue = poll_queues[idx++]; + odp_event_t buf; + + buf = odp_queue_deq(queue); + + if (ODP_EVENT_INVALID != buf) { + *from = queue; + return buf; + } + } + + *from = ODP_QUEUE_INVALID; + return ODP_EVENT_INVALID; +} + +/** + * IPsec pre argument processing initialization + */ +static +void ipsec_init_pre(void) +{ + odp_queue_param_t qparam; + + /* + * Create queues + * + * - completion queue (should eventually be ORDERED) + * - sequence number queue (must be ATOMIC) + */ + odp_queue_param_init(&qparam); + qparam.type = ODP_QUEUE_TYPE_SCHED; + qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; + qparam.sched.group = ODP_SCHED_GROUP_ALL; + + completionq = queue_create("completion", &qparam); + if (ODP_QUEUE_INVALID == completionq) { + EXAMPLE_ERR("Error: completion queue creation failed\n"); + exit(EXIT_FAILURE); + } + + qparam.type = ODP_QUEUE_TYPE_SCHED; + qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST; + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; + qparam.sched.group = ODP_SCHED_GROUP_ALL; + + /* 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 + * + * @param api_mode Mode to use for IPsec operation + */ +static +void ipsec_init_post(odp_ipsec_op_mode_t api_mode) +{ + sp_db_entry_t *entry; + odp_ipsec_config_t ipsec_config; + odp_ipsec_capability_t ipsec_cap; + + if (odp_ipsec_capability(&ipsec_cap) != ODP_IPSEC_OK) { + EXAMPLE_ERR("Error: failure getting IPSec caps\n"); + exit(EXIT_FAILURE); + } + + odp_ipsec_config_init(&ipsec_config); + ipsec_config.inbound.parse_level = ODP_PROTO_LAYER_ALL; + ipsec_config.inbound_mode = api_mode; + ipsec_config.outbound_mode = api_mode; + ipsec_config.inbound.default_queue = completionq; + if (odp_ipsec_config(&ipsec_config) != ODP_IPSEC_OK) { + EXAMPLE_ERR("Error: failure setting IPSec config\n"); + exit(EXIT_FAILURE); + } + + /* Attempt to find appropriate SA for each SP */ + for (entry = sp_db->list; NULL != entry; entry = entry->next) { + sa_db_entry_t *cipher_sa = NULL; + sa_db_entry_t *auth_sa = NULL; + tun_db_entry_t *tun = NULL; + + if (entry->esp) { + cipher_sa = find_sa_db_entry(&entry->src_subnet, + &entry->dst_subnet, + 1); + tun = find_tun_db_entry(cipher_sa->src_ip, + cipher_sa->dst_ip); + } + if (entry->ah) { + auth_sa = find_sa_db_entry(&entry->src_subnet, + &entry->dst_subnet, + 0); + tun = find_tun_db_entry(auth_sa->src_ip, + auth_sa->dst_ip); + } + + if (cipher_sa || auth_sa) { + if (create_ipsec_cache_entry(cipher_sa, + auth_sa, + tun, + entry->input, + completionq)) { + EXAMPLE_ERR("Error: IPSec cache entry failed.\n" + ); + exit(EXIT_FAILURE); + } + } else { + printf(" WARNING: SA not found for SP\n"); + dump_sp_db_entry(entry); + } + } +} + +static +int check_stream_db_in(const char *intf) +{ + stream_db_entry_t *stream = NULL; + + /* For each stream look for input and output IPsec entries */ + for (stream = stream_db->list; NULL != stream; stream = stream->next) { + if (!strcmp(stream->input.intf, intf)) + return 1; + } + + return 0; +} + +static +int check_stream_db_out(const char *intf) +{ + stream_db_entry_t *stream = NULL; + + /* For each stream look for input and output IPsec entries */ + for (stream = stream_db->list; NULL != stream; stream = stream->next) { + if (!strcmp(stream->output.intf, intf)) + return 1; + } + + return 0; +} + +/** + * Initialize interface + * + * Initialize ODP pktio and queues, query MAC address and update + * forwarding database. + * + * @param intf Interface name string + */ +static +void initialize_intf(char *intf) +{ + odp_pktio_t pktio; + odp_pktout_queue_t pktout; + odp_queue_t inq; + int ret; + uint8_t src_mac[ODPH_ETHADDR_LEN]; + char src_mac_str[MAX_STRING]; + odp_pktio_param_t pktio_param; + odp_pktin_queue_param_t pktin_param; + odp_pktio_capability_t capa; + odp_pktio_config_t config; + + odp_pktio_param_init(&pktio_param); + + if (getenv("ODP_IPSEC_USE_POLL_QUEUES") || + check_stream_db_out(intf)) + pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE; + else + pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; + + /* + * Open a packet IO instance for thread and get default output queue + */ + pktio = odp_pktio_open(intf, pkt_pool, &pktio_param); + if (ODP_PKTIO_INVALID == pktio) { + EXAMPLE_ERR("Error: pktio create failed for %s\n", intf); + exit(EXIT_FAILURE); + } + + odp_pktin_queue_param_init(&pktin_param); + pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC; + + if (odp_pktin_queue_config(pktio, &pktin_param)) { + EXAMPLE_ERR("Error: pktin config failed for %s\n", intf); + exit(EXIT_FAILURE); + } + + if (odp_pktout_queue_config(pktio, NULL)) { + EXAMPLE_ERR("Error: pktout config failed for %s\n", intf); + exit(EXIT_FAILURE); + } + + if (odp_pktin_event_queue(pktio, &inq, 1) != 1) { + EXAMPLE_ERR("Error: failed to get input queue for %s\n", intf); + exit(EXIT_FAILURE); + } + + if (odp_pktout_queue(pktio, &pktout, 1) != 1) { + EXAMPLE_ERR("Error: failed to get pktout queue for %s\n", intf); + exit(EXIT_FAILURE); + } + + if (odp_pktio_capability(pktio, &capa) != 0) { + EXAMPLE_ERR("Error: failed to get capabilities for %s\n", intf); + exit(EXIT_FAILURE); + } + + odp_pktio_config_init(&config); + if (check_stream_db_in(intf) && + args->appl.mode == ODP_IPSEC_OP_MODE_INLINE) + config.inbound_ipsec = capa.config.inbound_ipsec; + if (check_stream_db_out(intf) && + args->appl.mode == ODP_IPSEC_OP_MODE_INLINE) + config.outbound_ipsec = capa.config.outbound_ipsec; + + if (odp_pktio_config(pktio, &config) != 0) { + EXAMPLE_ERR("Error: failed to set config for %s\n", intf); + exit(EXIT_FAILURE); + } + + ret = odp_pktio_start(pktio); + if (ret) { + EXAMPLE_ERR("Error: unable to start %s\n", intf); + exit(EXIT_FAILURE); + } + + /* Read the source MAC address for this interface */ + ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac)); + if (ret <= 0) { + EXAMPLE_ERR("Error: failed during MAC address get for %s\n", + intf); + exit(EXIT_FAILURE); + } + + printf("Created pktio:%02" PRIu64 ", queue mode (ATOMIC queues)\n" + " default pktio%02" PRIu64 "-INPUT queue:%" PRIu64 "\n" + " source mac address %s\n", + odp_pktio_to_u64(pktio), odp_pktio_to_u64(pktio), + odp_queue_to_u64(inq), + mac_addr_str(src_mac_str, src_mac)); + + /* Resolve any routes using this interface for output */ + resolve_fwd_db(intf, pktio, pktout, src_mac); +} + +/** + * Packet Processing - Input verification + * + * @param pkt Packet to inspect + * @param ctx Packet process context (not used) + * + * @return PKT_CONTINUE if good, supported packet else PKT_DROP + */ +static +pkt_disposition_e do_input_verify(odp_packet_t pkt, + pkt_ctx_t *ctx EXAMPLE_UNUSED) +{ + if (odp_unlikely(odp_packet_has_error(pkt))) + return PKT_DROP; + + if (!odp_packet_has_eth(pkt)) + return PKT_DROP; + + if (!odp_packet_has_ipv4(pkt)) + return PKT_DROP; + + return PKT_CONTINUE; +} + +/** + * Packet Processing - Route lookup in forwarding database + * + * @param pkt Packet to route + * @param ctx Packet process context + * + * @return PKT_CONTINUE if route found else PKT_DROP + */ +static +pkt_disposition_e do_route_fwd_db(odp_packet_t pkt, pkt_ctx_t *ctx) +{ + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); + fwd_db_entry_t *entry; + + entry = find_fwd_db_entry(odp_be_to_cpu_32(ip->dst_addr)); + + if (entry) { + uint32_t l3_offset = odp_packet_l3_offset(pkt); + + if (l3_offset > sizeof(odph_ethhdr_t)) + odp_packet_pull_head(pkt, + l3_offset - sizeof(odph_ethhdr_t)); + else + odp_packet_push_head(pkt, + sizeof(odph_ethhdr_t) - l3_offset); + + memcpy(&ctx->eth.dst, entry->dst_mac, ODPH_ETHADDR_LEN); + memcpy(&ctx->eth.src, entry->src_mac, ODPH_ETHADDR_LEN); + ctx->eth.type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4); + + if (args->appl.mode != ODP_IPSEC_OP_MODE_INLINE) { + odp_packet_l2_offset_set(pkt, 0); + odp_packet_copy_from_mem(pkt, 0, ODPH_ETHHDR_LEN, + &ctx->eth); + } + + ctx->pktio = entry->pktio; + ctx->pktout = entry->pktout; + + return PKT_CONTINUE; + } + + return PKT_DROP; +} + +/** + * Packet Processing - Input IPsec packet classification + * + * Verify the received packet has IPsec headers and a match + * in the IPsec cache, if so issue crypto request else skip + * input crypto. + * + * @param pkt Packet to classify + * @param ctx Packet process context + * + * @return PKT_CONTINUE if done else PKT_POSTED + */ +static +pkt_disposition_e do_ipsec_in_classify(odp_packet_t *ppkt) +{ + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*ppkt, NULL); + odph_ahhdr_t *ah = NULL; + odph_esphdr_t *esp = NULL; + ipsec_cache_entry_t *entry; + odp_ipsec_in_param_t in_param; + int rc; + + /* Check IP header for IPSec protocols and look it up */ + locate_ipsec_headers(ip, &ah, &esp); + if (!ah && !esp) + return PKT_CONTINUE; + entry = find_ipsec_cache_entry_in(odp_be_to_cpu_32(ip->src_addr), + odp_be_to_cpu_32(ip->dst_addr), + ah, + esp); + if (!entry) + return PKT_CONTINUE; + + memset(&in_param, 0, sizeof(in_param)); + if (args->appl.lookup) { + in_param.num_sa = 0; + in_param.sa = NULL; + } else { + in_param.num_sa = 1; + in_param.sa = &entry->ipsec_sa; + } + + /* Issue crypto request */ + if (args->appl.mode != ODP_IPSEC_OP_MODE_SYNC) { + rc = odp_ipsec_in_enq(ppkt, 1, &in_param); + if (rc <= 0) + return PKT_DROP; + + return PKT_POSTED; + } else { + int out = 1; + + rc = odp_ipsec_in(ppkt, 1, ppkt, &out, &in_param); + if (rc <= 0) + return PKT_DROP; + + return PKT_CONTINUE; + } +} + +/** + * Packet Processing - Output IPsec packet classification + * + * Verify the outbound packet has a match in the IPsec cache, + * if so issue prepend IPsec headers and prepare parameters + * for crypto API call. Post the packet to ATOMIC queue so + * that sequence numbers can be applied in packet order as + * the next processing step. + * + * @param pkt Packet to classify + * @param ctx Packet process context + * + * @return PKT_CONTINUE if done else PKT_POSTED + */ +static +pkt_disposition_e do_ipsec_out_classify(odp_packet_t *ppkt, pkt_ctx_t *ctx) +{ + odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*ppkt, NULL); + ipsec_cache_entry_t *entry; + odp_ipsec_out_param_t out_param; + int rc; + + /* Find record */ + entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr), + odp_be_to_cpu_32(ip->dst_addr), + ip->proto); + if (!entry) + return PKT_CONTINUE; + + memset(&out_param, 0, sizeof(out_param)); + out_param.num_sa = 1; + out_param.num_opt = 0; + out_param.sa = &entry->ipsec_sa; + out_param.opt = NULL; + + /* Issue crypto request */ + if (args->appl.mode == ODP_IPSEC_OP_MODE_INLINE) { + odp_ipsec_out_inline_param_t inline_param; + + inline_param.pktio = ctx->pktio; + inline_param.outer_hdr.ptr = (void *)&ctx->eth; + inline_param.outer_hdr.len = ODPH_ETHHDR_LEN; + rc = odp_ipsec_out_inline(ppkt, 1, &out_param, &inline_param); + if (rc <= 0) + return PKT_DROP; + + return PKT_DONE; + } else if (args->appl.mode != ODP_IPSEC_OP_MODE_SYNC) { + rc = odp_ipsec_out_enq(ppkt, 1, &out_param); + if (rc <= 0) + return PKT_DROP; + + return PKT_POSTED; + } else { + int out = 1; + + rc = odp_ipsec_out(ppkt, 1, ppkt, &out, &out_param); + if (rc <= 0) + return PKT_DROP; + + return PKT_CONTINUE; + } +} + +/** + * Packet IO worker thread + * + * Loop calling odp_schedule to obtain packets from one of three sources, + * and continue processing the packet based on the state stored in its + * per packet context. + * + * - Input interfaces (i.e. new work) + * - Sequence number assignment queue + * - Per packet crypto API completion queue + * + * @param arg Required by "odph_odpthreads_create", unused + * + * @return NULL (should never return) + */ +static +int pktio_thread(void *arg EXAMPLE_UNUSED) +{ + int thr; + odp_packet_t pkt; + odp_event_t ev; + unsigned long pkt_cnt = 0; + + thr = odp_thread_id(); + + printf("Pktio thread [%02i] starts\n", thr); + + odp_barrier_wait(&sync_barrier); + + /* Loop packets */ + for (;;) { + pkt_disposition_e rc = PKT_CONTINUE; + pkt_ctx_t *ctx; + odp_queue_t dispatchq; + odp_event_subtype_t subtype; + + /* Use schedule to get event from any input queue */ + ev = schedule(&dispatchq); + + /* Determine new work versus completion or sequence number */ + if (ODP_EVENT_PACKET == odp_event_types(ev, &subtype)) { + pkt = odp_packet_from_event(ev); + if (ODP_EVENT_PACKET_BASIC == subtype) { + ctx = alloc_pkt_ctx(pkt); + if (!ctx) { + odp_packet_free(pkt); + continue; + } + ctx->state = PKT_STATE_INPUT_VERIFY; + } else if (ODP_EVENT_PACKET_IPSEC == subtype) { + odp_ipsec_packet_result_t result; + + if (odp_unlikely(odp_ipsec_result(&result, + pkt) < 0)) { + EXAMPLE_DBG("Error Event\n"); + odp_event_free(ev); + continue; + } + + if (result.status.error.all != 0) { + EXAMPLE_DBG("Error in IPsec\n"); + rc = PKT_DROP; + } + + if (result.flag.inline_mode) { + ctx = alloc_pkt_ctx(pkt); + if (!ctx) { + odp_packet_free(pkt); + continue; + } + if (odp_unlikely( + odp_packet_has_error(pkt) || + !odp_packet_has_ipv4(pkt))) + rc = PKT_DROP; + ctx->state = PKT_STATE_ROUTE_LOOKUP; + } else { + ctx = odp_packet_user_ptr(pkt); + } + } else { + EXAMPLE_DBG("Unsupported Packet\n"); + odp_event_free(ev); + continue; + } + } else if (ODP_EVENT_IPSEC_STATUS == odp_event_type(ev)) { + odp_ipsec_status_t status; + + if (odp_unlikely(odp_ipsec_status(&status, ev) < 0)) { + EXAMPLE_DBG("Error Event\n"); + odp_event_free(ev); + continue; + } + + printf("IPsec status %d result %d for SA %" PRIx64 "\n", + status.id, status.result, + odp_ipsec_sa_to_u64(status.sa)); + + odp_event_free(ev); + continue; + } else { + abort(); + } + + /* + * We now have a packet and its associated context. Loop here + * executing processing based on the current state value stored + * in the context as long as the processing return code + * indicates PKT_CONTINUE. + * + * For other return codes: + * + * o PKT_DONE - finished with the packet + * o PKT_DROP - something incorrect about the packet, drop it + * o PKT_POSTED - packet/event has been queued for later + */ + while (rc == PKT_CONTINUE) { + switch (ctx->state) { + case PKT_STATE_INPUT_VERIFY: + + rc = do_input_verify(pkt, ctx); + ctx->state = PKT_STATE_IPSEC_IN_CLASSIFY; + break; + + case PKT_STATE_IPSEC_IN_CLASSIFY: + + ctx->state = PKT_STATE_ROUTE_LOOKUP; + rc = do_ipsec_in_classify(&pkt); + break; + + case PKT_STATE_ROUTE_LOOKUP: + + rc = do_route_fwd_db(pkt, ctx); + ctx->state = PKT_STATE_IPSEC_OUT_CLASSIFY; + break; + + case PKT_STATE_IPSEC_OUT_CLASSIFY: + ctx->state = PKT_STATE_TRANSMIT; + rc = do_ipsec_out_classify(&pkt, ctx); + break; + + case PKT_STATE_TRANSMIT: + + if (odp_pktout_send(ctx->pktout, &pkt, 1) < 1) + rc = PKT_DROP; + else + rc = PKT_DONE; + break; + + default: + rc = PKT_DROP; + break; + } + } + + /* Free context on drop or transmit */ + if ((PKT_DROP == rc) || (PKT_DONE == rc)) + free_pkt_ctx(ctx); + + /* Check for drop */ + if (PKT_DROP == rc) + odp_packet_free(pkt); + + /* Print packet counts every once in a while */ + if (PKT_DONE == rc) { + if (odp_unlikely(pkt_cnt++ % 1000 == 0)) { + printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); + fflush(NULL); + } + } + } + + /* unreachable */ + return 0; +} + +/** + * ODP ipsec example main function + */ +int +main(int argc, char *argv[]) +{ + odph_odpthread_t thread_tbl[MAX_WORKERS]; + int num_workers; + int i; + int stream_count; + odp_shm_t shm; + odp_cpumask_t cpumask; + char cpumaskstr[ODP_CPUMASK_STR_SIZE]; + odp_pool_param_t params; + odp_instance_t instance; + odph_odpthread_params_t thr_params; + + /* create by default scheduled queues */ + queue_create = odp_queue_create; + schedule = odp_schedule_cb; + + /* check for using poll queues */ + if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) { + queue_create = polled_odp_queue_create; + schedule = polled_odp_schedule_cb; + } + + /* Init ODP before calling anything else */ + if (odp_init_global(&instance, NULL, NULL)) { + EXAMPLE_ERR("Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Init this thread */ + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + EXAMPLE_ERR("Error: ODP local init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Reserve memory for args from shared mem */ + shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE, + 0); + + args = odp_shm_addr(shm); + + if (NULL == args) { + EXAMPLE_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(args, 0, sizeof(*args)); + + /* Must init our databases before parsing args */ + ipsec_init_pre(); + init_fwd_db(); + init_stream_db(); + + /* Parse and store the application arguments */ + parse_args(argc, argv, &args->appl); + + /* Print both system and application information */ + print_info(NO_PATH(argv[0]), &args->appl); + + /* Default to system CPU count unless user specified */ + num_workers = MAX_WORKERS; + if (args->appl.cpu_count) + num_workers = args->appl.cpu_count; + + /* Get default worker cpumask */ + num_workers = odp_cpumask_default_worker(&cpumask, num_workers); + (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr)); + + printf("num worker threads: %i\n", num_workers); + printf("first CPU: %i\n", odp_cpumask_first(&cpumask)); + printf("cpu mask: %s\n", cpumaskstr); + + /* Create a barrier to synchronize thread startup */ + odp_barrier_init(&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_ERR("Error: packet pool create failed.\n"); + exit(EXIT_FAILURE); + } + + /* Create context buffer pool */ + params.buf.size = SHM_CTX_POOL_BUF_SIZE; + params.buf.align = 0; + params.buf.num = SHM_CTX_POOL_BUF_COUNT; + params.type = ODP_POOL_BUFFER; + + ctx_pool = odp_pool_create("ctx_pool", ¶ms); + + if (ODP_POOL_INVALID == ctx_pool) { + EXAMPLE_ERR("Error: context pool create failed.\n"); + exit(EXIT_FAILURE); + } + + /* Populate our IPsec cache */ + printf("Using %s mode for IPsec API\n\n", + (ODP_IPSEC_OP_MODE_SYNC == args->appl.mode) ? "SYNC" : + (ODP_IPSEC_OP_MODE_ASYNC == args->appl.mode) ? "ASYNC" : + "INLINE"); + ipsec_init_post(args->appl.mode); + + /* Initialize interfaces (which resolves FWD DB entries */ + for (i = 0; i < args->appl.if_count; i++) + initialize_intf(args->appl.if_names[i]); + + /* If we have test streams build them before starting workers */ + resolve_stream_db(); + stream_count = create_stream_db_inputs(); + + /* + * Create and init worker threads + */ + memset(&thr_params, 0, sizeof(thr_params)); + thr_params.start = pktio_thread; + thr_params.arg = NULL; + thr_params.thr_type = ODP_THREAD_WORKER; + thr_params.instance = instance; + odph_odpthreads_create(thread_tbl, &cpumask, &thr_params); + + /* + * If there are streams attempt to verify them else + * wait indefinitely + */ + if (stream_count) { + odp_bool_t done; + + do { + done = verify_stream_db_outputs(); + sleep(1); + } while (!done); + printf("All received\n"); + } else { + odph_odpthreads_join(thread_tbl); + } + + free(args->appl.if_names); + free(args->appl.if_str); + + shm = odp_shm_lookup("shm_args"); + if (odp_shm_free(shm) != 0) + EXAMPLE_ERR("Error: shm free shm_args failed\n"); + shm = odp_shm_lookup("shm_ipsec_cache"); + if (odp_shm_free(shm) != 0) + EXAMPLE_ERR("Error: shm free shm_ipsec_cache failed\n"); + shm = odp_shm_lookup("shm_fwd_db"); + if (odp_shm_free(shm) != 0) + EXAMPLE_ERR("Error: shm free shm_fwd_db failed\n"); + shm = odp_shm_lookup("shm_sa_db"); + if (odp_shm_free(shm) != 0) + EXAMPLE_ERR("Error: shm free shm_sa_db failed\n"); + shm = odp_shm_lookup("shm_tun_db"); + if (odp_shm_free(shm) != 0) + EXAMPLE_ERR("Error: shm free shm_tun_db failed\n"); + shm = odp_shm_lookup("shm_sp_db"); + if (odp_shm_free(shm) != 0) + EXAMPLE_ERR("Error: shm free shm_sp_db failed\n"); + shm = odp_shm_lookup("stream_db"); + if (odp_shm_free(shm) != 0) + EXAMPLE_ERR("Error: shm free stream_db failed\n"); + + printf("Exit\n\n"); + + return 0; +} + +/** + * Parse and store the command line arguments + * + * @param argc argument count + * @param argv[] argument vector + * @param appl_args Store application arguments here + */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) +{ + int opt; + int long_index; + char *token; + size_t len; + int rc = 0; + int i; + + static const struct option longopts[] = { + {"count", required_argument, NULL, 'c'}, + {"interface", required_argument, NULL, 'i'}, /* return 'i' */ + {"lookup", 0, NULL, 'l'}, + {"mode", required_argument, NULL, 'm'}, /* return 'm' */ + {"route", required_argument, NULL, 'r'}, /* return 'r' */ + {"policy", required_argument, NULL, 'p'}, /* return 'p' */ + {"ah", required_argument, NULL, 'a'}, /* return 'a' */ + {"esp", required_argument, NULL, 'e'}, /* return 'e' */ + {"tunnel", required_argument, NULL, 't'}, /* return 't' */ + {"stream", required_argument, NULL, 's'}, /* return 's' */ + {"help", no_argument, NULL, 'h'}, /* return 'h' */ + {NULL, 0, NULL, 0} + }; + + static const char *shortopts = "+c:i:h:lm:r:p:a:e:t:s:"; + + /* let helper collect its own arguments (e.g. --odph_proc) */ + odph_parse_options(argc, argv, shortopts, longopts); + + printf("\nParsing command line options\n"); + + opterr = 0; /* do not issue errors on helper options */ + + while (!rc) { + opt = getopt_long(argc, argv, shortopts, longopts, &long_index); + + if (-1 == opt) + break; /* No more options */ + + switch (opt) { + case 'c': + appl_args->cpu_count = atoi(optarg); + break; + /* parse packet-io interface names */ + case 'i': + len = strlen(optarg); + if (0 == len) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + len += 1; /* add room for '\0' */ + + appl_args->if_str = malloc(len); + if (appl_args->if_str == NULL) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* count the number of tokens separated by ',' */ + strcpy(appl_args->if_str, optarg); + for (token = strtok(appl_args->if_str, ","), i = 0; + token != NULL; + token = strtok(NULL, ","), i++) + ; + + appl_args->if_count = i; + + if (0 == appl_args->if_count) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* allocate storage for the if names */ + appl_args->if_names = + calloc(appl_args->if_count, sizeof(char *)); + + /* store the if names (reset names string) */ + strcpy(appl_args->if_str, optarg); + for (token = strtok(appl_args->if_str, ","), i = 0; + token != NULL; token = strtok(NULL, ","), i++) { + appl_args->if_names[i] = token; + } + break; + + case 'l': + appl_args->lookup = true; + break; + + case 'm': + appl_args->mode = atoi(optarg); + break; + + case 'r': + rc = create_fwd_db_entry(optarg, appl_args->if_names, + appl_args->if_count); + break; + + case 'p': + rc = create_sp_db_entry(optarg); + break; + + case 'a': + rc = create_sa_db_entry(optarg, FALSE); + break; + + case 'e': + rc = create_sa_db_entry(optarg, TRUE); + break; + + case 't': + rc = create_tun_db_entry(optarg); + break; + + case 's': + rc = create_stream_db_entry(optarg); + break; + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + + default: + break; + } + } + + if (rc) { + printf("ERROR: failed parsing -%c option\n", opt); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (0 == appl_args->if_count) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + optind = 1; /* reset 'extern optind' from the getopt lib */ +} + +/** + * Print system and application info + */ +static void print_info(char *progname, appl_args_t *appl_args) +{ + int i; + + odp_sys_info_print(); + + printf("Running ODP appl: \"%s\"\n" + "-----------------\n" + "IF-count: %i\n" + "Using IFs: ", + progname, appl_args->if_count); + for (i = 0; i < appl_args->if_count; ++i) + printf(" %s", appl_args->if_names[i]); + + printf("\n"); + + dump_fwd_db(); + dump_sp_db(); + dump_sa_db(); + dump_tun_db(); + printf("\n\n"); + fflush(NULL); +} + +/** + * Prinf usage information + */ +static void usage(char *progname) +{ + printf("\n" + "Usage: %s OPTIONS\n" + " E.g. %s -i eth1,eth2,eth3 -m 0\n" + "\n" + "OpenDataPlane example application.\n" + "\n" + "Mandatory OPTIONS:\n" + " -i, --interface Eth interfaces (comma-separated, no spaces)\n" + " -m, --mode 0: SYNC\n" + " 1: ASYNC\n" + " Default: 1: ASYNC api mode\n" + "\n" + "Routing / IPSec OPTIONS:\n" + " -r, --route SubNet:Intf:NextHopMAC\n" + " -p, --policy SrcSubNet:DstSubNet:(in|out):(ah|esp|both)\n" + " -e, --esp SrcIP:DstIP:(3des|null):SPI:Key192\n" + " -a, --ah SrcIP:DstIP:(sha256|md5|null):SPI:Key(256|128)\n" + "\n" + " Where: NextHopMAC is raw hex/dot notation, i.e. 03.BA.44.9A.CE.02\n" + " IP is decimal/dot notation, i.e. 192.168.1.1\n" + " SubNet is decimal/dot/slash notation, i.e 192.168.0.0/16\n" + " SPI is raw hex, 32 bits\n" + " KeyXXX is raw hex, XXX bits long\n" + "\n" + " Examples:\n" + " -r 192.168.222.0/24:p8p1:08.00.27.F5.8B.DB\n" + " -p 192.168.111.0/24:192.168.222.0/24:out:esp\n" + " -e 192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n" + " -a 192.168.111.2:192.168.222.2:md5:201:a731649644c5dee92cbd9c2e7e188ee6\n" + "\n" + "Optional OPTIONS\n" + " -c, --count CPU count.\n" + " -h, --help Display help and exit.\n" + " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n" + " to enable use of poll queues instead of scheduled (default)\n" + " ODP_IPSEC_STREAM_VERIFY_MDEQ\n" + " to enable use of multiple dequeue for queue draining during\n" + " stream verification instead of single dequeue (default)\n" + "\n", NO_PATH(progname), NO_PATH(progname) + ); +} diff --git a/example/ipsec_api/odp_ipsec_cache.c b/example/ipsec_api/odp_ipsec_cache.c new file mode 100644 index 00000000000..a9cf62dda3d --- /dev/null +++ b/example/ipsec_api/odp_ipsec_cache.c @@ -0,0 +1,180 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#include + +#include + +#include + +/** Global pointer to ipsec_cache db */ +ipsec_cache_t *ipsec_cache; + +void init_ipsec_cache(void) +{ + odp_shm_t shm; + + 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_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + 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 param; + ipsec_cache_entry_t *entry; + odp_ipsec_sa_t ipsec_sa; + uint32_t tun_src_ip, tun_dst_ip; + sa_mode_t mode = IPSEC_SA_MODE_TRANSPORT; + + /* Verify we have a good entry */ + entry = &ipsec_cache->array[ipsec_cache->index]; + if (MAX_DB <= ipsec_cache->index) + return -1; + + odp_ipsec_sa_param_init(¶m); + param.dir = in ? ODP_IPSEC_DIR_INBOUND : ODP_IPSEC_DIR_OUTBOUND; + param.inbound.lookup_mode = in ? ODP_IPSEC_LOOKUP_SPI : + ODP_IPSEC_LOOKUP_DISABLED; + param.proto = cipher_sa ? ODP_IPSEC_ESP : ODP_IPSEC_AH; + + param.mode = tun ? ODP_IPSEC_MODE_TUNNEL : ODP_IPSEC_MODE_TRANSPORT; + + param.dest_queue = completionq; + + /* Cipher */ + if (cipher_sa) { + param.crypto.cipher_alg = cipher_sa->alg.u.cipher; + param.crypto.cipher_key.data = cipher_sa->key.data; + param.crypto.cipher_key.length = cipher_sa->key.length; + param.spi = cipher_sa->spi; + } else { + param.crypto.cipher_alg = ODP_CIPHER_ALG_NULL; + } + + /* Auth */ + if (auth_sa) { + param.crypto.auth_alg = auth_sa->alg.u.auth; + param.crypto.auth_key.data = auth_sa->key.data; + param.crypto.auth_key.length = auth_sa->key.length; + param.spi = auth_sa->spi; + } else { + param.crypto.auth_alg = ODP_AUTH_ALG_NULL; + } + + if (ODP_IPSEC_MODE_TUNNEL == param.mode) { + tun_src_ip = odp_cpu_to_be_32(tun->tun_src_ip); + tun_dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip); + param.outbound.tunnel.type = ODP_IPSEC_TUNNEL_IPV4; + param.outbound.tunnel.ipv4.src_addr = &tun_src_ip; + param.outbound.tunnel.ipv4.dst_addr = &tun_dst_ip; + } + + ipsec_sa = odp_ipsec_sa_create(¶m); + if (ODP_IPSEC_SA_INVALID == ipsec_sa) { + EXAMPLE_ERR("Error: SA creation failed\n"); + exit(EXIT_FAILURE); + } + + /* Copy remainder */ + if (cipher_sa) { + entry->src_ip = cipher_sa->src_ip; + entry->dst_ip = cipher_sa->dst_ip; + entry->esp.alg = cipher_sa->alg.u.cipher; + entry->esp.spi = cipher_sa->spi; + entry->esp.block_len = cipher_sa->block_len; + entry->esp.iv_len = cipher_sa->iv_len; + memcpy(&entry->esp.key, &cipher_sa->key, sizeof(ipsec_key_t)); + } + if (auth_sa) { + entry->src_ip = auth_sa->src_ip; + entry->dst_ip = auth_sa->dst_ip; + entry->ah.alg = auth_sa->alg.u.auth; + entry->ah.spi = auth_sa->spi; + entry->ah.icv_len = auth_sa->icv_len; + memcpy(&entry->ah.key, &auth_sa->key, sizeof(ipsec_key_t)); + } + + if (tun) { + entry->tun_src_ip = tun->tun_src_ip; + entry->tun_dst_ip = tun->tun_dst_ip; + mode = IPSEC_SA_MODE_TUNNEL; + } + entry->mode = mode; + + /* 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; + } + + entry->ipsec_sa = ipsec_sa; + + return 0; +} + +ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip, + uint32_t dst_ip, + odph_ahhdr_t *ah, + odph_esphdr_t *esp) +{ + ipsec_cache_entry_t *entry = ipsec_cache->in_list; + + /* Look for a hit */ + for (; NULL != entry; entry = entry->next) { + if ((entry->src_ip != src_ip) || (entry->dst_ip != dst_ip)) + if ((entry->tun_src_ip != src_ip) || + (entry->tun_dst_ip != dst_ip)) + continue; + if (ah && + ((!entry->ah.alg) || + (entry->ah.spi != odp_be_to_cpu_32(ah->spi)))) + continue; + if (esp && + ((!entry->esp.alg) || + (entry->esp.spi != odp_be_to_cpu_32(esp->spi)))) + continue; + break; + } + + return entry; +} + +ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip, + uint32_t dst_ip, + uint8_t proto EXAMPLE_UNUSED) +{ + ipsec_cache_entry_t *entry = ipsec_cache->out_list; + + /* Look for a hit */ + for (; NULL != entry; entry = entry->next) { + if ((entry->src_ip == src_ip) && (entry->dst_ip == dst_ip)) + break; + } + return entry; +} diff --git a/example/ipsec_api/odp_ipsec_cache.h b/example/ipsec_api/odp_ipsec_cache.h new file mode 100644 index 00000000000..91064de6e09 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_cache.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_IPSEC_CACHE_H_ +#define ODP_IPSEC_CACHE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +/** + * 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 */ + sa_mode_t mode; /**< SA mode - transport/tun */ + uint32_t tun_src_ip; /**< Tunnel src IPv4 addr */ + uint32_t tun_dst_ip; /**< Tunnel dst IPv4 addr */ + struct { + odp_cipher_alg_t alg; /**< Cipher algorithm */ + uint32_t spi; /**< Cipher SPI */ + uint32_t block_len; /**< Cipher block length */ + uint32_t iv_len; /**< Cipher IV length */ + ipsec_key_t key; /**< Cipher key */ + } esp; + struct { + odp_auth_alg_t alg; /**< Auth algorithm */ + uint32_t spi; /**< Auth SPI */ + uint32_t icv_len; /**< Auth ICV length */ + ipsec_key_t key; /**< Auth key */ + } ah; + + odp_ipsec_sa_t ipsec_sa; +} 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 input packet + * + * @param src_ip Source IPv4 address + * @param dst_ip Destination IPv4 address + * @param ah Pointer to AH header in packet else NULL + * @param esp Pointer to ESP header in packet else NULL + * + * @return pointer to IPsec cache entry else NULL + */ +ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip, + uint32_t dst_ip, + odph_ahhdr_t *ah, + odph_esphdr_t *esp); + +/** + * Find a matching IPsec cache entry for output packet + * + * @param src_ip Source IPv4 address + * @param dst_ip Destination IPv4 address + * @param proto IPv4 protocol (currently all protocols match) + * + * @return pointer to IPsec cache entry else NULL + */ +ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip, + uint32_t dst_ip, + uint8_t proto); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/ipsec_api/odp_ipsec_fwd_db.c b/example/ipsec_api/odp_ipsec_fwd_db.c new file mode 120000 index 00000000000..63b0d36d63b --- /dev/null +++ b/example/ipsec_api/odp_ipsec_fwd_db.c @@ -0,0 +1 @@ +../ipsec/odp_ipsec_fwd_db.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_fwd_db.h b/example/ipsec_api/odp_ipsec_fwd_db.h new file mode 120000 index 00000000000..5a709f21220 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_fwd_db.h @@ -0,0 +1 @@ +../ipsec/odp_ipsec_fwd_db.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_misc.h b/example/ipsec_api/odp_ipsec_misc.h new file mode 120000 index 00000000000..f1de214a40e --- /dev/null +++ b/example/ipsec_api/odp_ipsec_misc.h @@ -0,0 +1 @@ +../ipsec/odp_ipsec_misc.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_run_ah_in.sh b/example/ipsec_api/odp_ipsec_run_ah_in.sh new file mode 100755 index 00000000000..c5b105f596a --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_ah_in.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Test input AH +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ +-p 192.168.222.0/24:192.168.111.0/24:in:ah \ +-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ +-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_ah_out.sh b/example/ipsec_api/odp_ipsec_run_ah_out.sh new file mode 100755 index 00000000000..c8926d5ac16 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_ah_out.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Test output AH +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:ah \ +-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_ah_tun_in.sh b/example/ipsec_api/odp_ipsec_run_ah_tun_in.sh new file mode 100755 index 00000000000..a0d4c4332fd --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_ah_tun_in.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Test input AH +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ +-p 192.168.222.0/24:192.168.111.0/24:in:ah \ +-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ +-t 192.168.222.2:192.168.111.2:10.0.222.2:10.0.111.2 \ +-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_ah_tun_out.sh b/example/ipsec_api/odp_ipsec_run_ah_tun_out.sh new file mode 100755 index 00000000000..74a0e3b42e5 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_ah_tun_out.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Test output AH +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:ah \ +-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ +-t 192.168.111.2:192.168.222.2:10.0.111.2:10.0.222.2 \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_esp_in.sh b/example/ipsec_api/odp_ipsec_run_esp_in.sh new file mode 100755 index 00000000000..39e171cdfb9 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_esp_in.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Test input ESP +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ +-p 192.168.222.0/24:192.168.111.0/24:in:esp \ +-e 192.168.222.2:192.168.111.2:\ +3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ +-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_esp_out.sh b/example/ipsec_api/odp_ipsec_run_esp_out.sh new file mode 100755 index 00000000000..98ab04e526b --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_esp_out.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Test output ESP +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:esp \ +-e 192.168.111.2:192.168.222.2:\ +3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_esp_tun_in.sh b/example/ipsec_api/odp_ipsec_run_esp_tun_in.sh new file mode 100755 index 00000000000..7ef3e2d080c --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_esp_tun_in.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# +# Test input ESP +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ +-p 192.168.222.0/24:192.168.111.0/24:in:esp \ +-e 192.168.222.2:192.168.111.2:\ +3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ +-t 192.168.222.2:192.168.111.2:10.0.222.2:10.0.111.2 \ +-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_esp_tun_out.sh b/example/ipsec_api/odp_ipsec_run_esp_tun_out.sh new file mode 100755 index 00000000000..98ab04e526b --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_esp_tun_out.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Test output ESP +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:esp \ +-e 192.168.111.2:192.168.222.2:\ +3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_live.sh b/example/ipsec_api/odp_ipsec_run_live.sh new file mode 100755 index 00000000000..b506b2af811 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_live.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Live router test +# - 2 interfaces interfaces +# - Specify API mode on command line +sudo odp_ipsec -i p7p1,p8p1 \ +-r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ +-r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ +-p 192.168.111.0/24:192.168.222.0/24:out:both \ +-e 192.168.111.2:192.168.222.2:\ +3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ +-p 192.168.222.0/24:192.168.111.0/24:in:both \ +-e 192.168.222.2:192.168.111.2:\ +3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ +-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_router.sh b/example/ipsec_api/odp_ipsec_run_router.sh new file mode 100755 index 00000000000..31b9e7656f9 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_router.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# +# Live router test +# - 2 interfaces interfaces +# - Specify API mode on command line +sudo odp_ipsec -i p7p1,p8p1 \ +-r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ +-r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ +-c 1 "$@" diff --git a/example/ipsec_api/odp_ipsec_run_simple.sh b/example/ipsec_api/odp_ipsec_run_simple.sh new file mode 100755 index 00000000000..ddda612a850 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_run_simple.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# +# Simple router test +# - 2 loop interfaces +# - 10 packets +# - Specify API mode on command line +odp_ipsec -i loop1,loop2 \ +-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ +-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_sa_db.c b/example/ipsec_api/odp_ipsec_sa_db.c new file mode 120000 index 00000000000..d9c593fa87a --- /dev/null +++ b/example/ipsec_api/odp_ipsec_sa_db.c @@ -0,0 +1 @@ +../ipsec/odp_ipsec_sa_db.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_sa_db.h b/example/ipsec_api/odp_ipsec_sa_db.h new file mode 120000 index 00000000000..57d50f3c28a --- /dev/null +++ b/example/ipsec_api/odp_ipsec_sa_db.h @@ -0,0 +1 @@ +../ipsec/odp_ipsec_sa_db.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_sp_db.c b/example/ipsec_api/odp_ipsec_sp_db.c new file mode 120000 index 00000000000..c4f785fa691 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_sp_db.c @@ -0,0 +1 @@ +../ipsec/odp_ipsec_sp_db.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_sp_db.h b/example/ipsec_api/odp_ipsec_sp_db.h new file mode 120000 index 00000000000..e37f784329e --- /dev/null +++ b/example/ipsec_api/odp_ipsec_sp_db.h @@ -0,0 +1 @@ +../ipsec/odp_ipsec_sp_db.h \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_stream.c b/example/ipsec_api/odp_ipsec_stream.c new file mode 120000 index 00000000000..4835150d1e8 --- /dev/null +++ b/example/ipsec_api/odp_ipsec_stream.c @@ -0,0 +1 @@ +../ipsec/odp_ipsec_stream.c \ No newline at end of file diff --git a/example/ipsec_api/odp_ipsec_stream.h b/example/ipsec_api/odp_ipsec_stream.h new file mode 120000 index 00000000000..1cabba28cdb --- /dev/null +++ b/example/ipsec_api/odp_ipsec_stream.h @@ -0,0 +1 @@ +../ipsec/odp_ipsec_stream.h \ No newline at end of file diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 index cab7f8b8c24..43853f7a0b8 100644 --- a/example/m4/configure.m4 +++ b/example/m4/configure.m4 @@ -11,6 +11,7 @@ AC_CONFIG_FILES([example/classifier/Makefile example/generator/Makefile example/hello/Makefile example/ipsec/Makefile + example/ipsec_api/Makefile example/ipfragreass/Makefile example/l2fwd_simple/Makefile example/l3fwd/Makefile From 2217d315e85c8c1f7d9986395a6bd2c9fb37e4af Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 13 Dec 2017 22:35:51 +0300 Subject: [PATCH 4/5] linux-gen: pktio: loop: reset flags before reparsing packtes Stale flags can interfere with packet processing, so let's reset them. Signed-off-by: Dmitry Eremin-Solenikov --- platform/linux-generic/pktio/loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index 698d363e4d6..8d27dd8b7d5 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -102,6 +102,7 @@ static int loopback_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED, pkt_len = odp_packet_len(pkt); pkt_hdr = odp_packet_hdr(pkt); + packet_parse_reset(pkt_hdr); if (pktio_cls_enabled(pktio_entry)) { odp_packet_t new_pkt; odp_pool_t new_pool; From af57e73c5f3b576b89236763ba649d6ed5d54d61 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 13 Dec 2017 22:38:10 +0300 Subject: [PATCH 5/5] linux-gen: pktio: loop: reset packet subtype to BASIC Signed-off-by: Dmitry Eremin-Solenikov --- platform/linux-generic/pktio/loop.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index 8d27dd8b7d5..ad2cb39f8a6 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -186,19 +186,18 @@ static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED, bytes += odp_packet_len(pkt_tbl[i]); } - if (pktio_entry->s.config.outbound_ipsec) - for (i = 0; i < len; ++i) { - odp_ipsec_packet_result_t result; + for (i = 0; i < len; ++i) { + odp_ipsec_packet_result_t result; - if (packet_subtype(pkt_tbl[i]) != - ODP_EVENT_PACKET_IPSEC) - continue; + if (packet_subtype(pkt_tbl[i]) == + ODP_EVENT_PACKET_IPSEC && + pktio_entry->s.config.outbound_ipsec) { /* Possibly postprocessing packet */ odp_ipsec_result(&result, pkt_tbl[i]); - - packet_subtype_set(pkt_tbl[i], ODP_EVENT_PACKET_BASIC); } + packet_subtype_set(pkt_tbl[i], ODP_EVENT_PACKET_BASIC); + } odp_ticketlock_lock(&pktio_entry->s.txl);