From dd9dc51b107bcf9ea6afb2d4fafd7c453f5cc240 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 8 Jan 2021 09:31:27 +0200 Subject: linux-gen: pool: add maximum packet length config option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configuration file option for the maximum packet data length in bytes. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- config/odp-linux-generic.conf | 5 ++++- platform/linux-generic/include/odp_config_internal.h | 5 ----- platform/linux-generic/include/odp_pool_internal.h | 1 + platform/linux-generic/m4/odp_libconfig.m4 | 2 +- platform/linux-generic/odp_pool.c | 18 ++++++++++++++++-- platform/linux-generic/odp_system_info.c | 1 - platform/linux-generic/test/inline-timer.conf | 2 +- platform/linux-generic/test/packet_align.conf | 2 +- platform/linux-generic/test/process-mode.conf | 2 +- 9 files changed, 25 insertions(+), 13 deletions(-) diff --git a/config/odp-linux-generic.conf b/config/odp-linux-generic.conf index ced837a29..a03c8568f 100644 --- a/config/odp-linux-generic.conf +++ b/config/odp-linux-generic.conf @@ -16,7 +16,7 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.13" +config_file_version = "0.1.14" # System options system: { @@ -72,6 +72,9 @@ pool: { # Packet pool options pkt: { + # Maximum packet data length in bytes + max_len = 65536 + # Maximum number of packets per pool. Power of two minus one # results optimal memory usage (e.g. (256 * 1024) - 1). max_num = 262143 diff --git a/platform/linux-generic/include/odp_config_internal.h b/platform/linux-generic/include/odp_config_internal.h index bd7f710d2..35f1c9142 100644 --- a/platform/linux-generic/include/odp_config_internal.h +++ b/platform/linux-generic/include/odp_config_internal.h @@ -91,11 +91,6 @@ extern "C" { */ #define CONFIG_PACKET_TAILROOM 0 -/* - * Maximum packet data length in bytes - */ -#define CONFIG_PACKET_MAX_LEN (64 * 1024) - /* * Maximum packet segment size including head- and tailrooms */ diff --git a/platform/linux-generic/include/odp_pool_internal.h b/platform/linux-generic/include/odp_pool_internal.h index a0b4591e3..9deb63cd0 100644 --- a/platform/linux-generic/include/odp_pool_internal.h +++ b/platform/linux-generic/include/odp_pool_internal.h @@ -104,6 +104,7 @@ typedef struct pool_global_t { odp_shm_t shm; struct { + uint32_t pkt_max_len; uint32_t pkt_max_num; uint32_t local_cache_size; uint32_t burst_size; diff --git a/platform/linux-generic/m4/odp_libconfig.m4 b/platform/linux-generic/m4/odp_libconfig.m4 index c3a83ed89..325c62ad0 100644 --- a/platform/linux-generic/m4/odp_libconfig.m4 +++ b/platform/linux-generic/m4/odp_libconfig.m4 @@ -3,7 +3,7 @@ ########################################################################## m4_define([_odp_config_version_generation], [0]) m4_define([_odp_config_version_major], [1]) -m4_define([_odp_config_version_minor], [13]) +m4_define([_odp_config_version_minor], [14]) m4_define([_odp_config_version], [_odp_config_version_generation._odp_config_version_major._odp_config_version_minor]) diff --git a/platform/linux-generic/odp_pool.c b/platform/linux-generic/odp_pool.c index d1fb7c933..9e6530eb6 100644 --- a/platform/linux-generic/odp_pool.c +++ b/platform/linux-generic/odp_pool.c @@ -210,6 +210,20 @@ static int read_config_file(pool_global_t *pool_glb) pool_glb->config.pkt_max_num = val; ODP_PRINT(" %s: %i\n", str, val); + str = "pool.pkt.max_len"; + if (!_odp_libconfig_lookup_int(str, &val)) { + ODP_ERR("Config option '%s' not found.\n", str); + return -1; + } + + if (val <= 0) { + ODP_ERR("Bad value %s = %i\n", str, val); + return -1; + } + + pool_glb->config.pkt_max_len = val; + ODP_PRINT(" %s: %i\n", str, val); + str = "pool.pkt.base_align"; if (!_odp_libconfig_lookup_int(str, &val)) { ODP_ERR("Config option '%s' not found.\n", str); @@ -571,7 +585,7 @@ static odp_pool_t pool_create(const char *name, const odp_pool_param_t *params, } seg_len = CONFIG_PACKET_MAX_SEG_LEN; - max_len = CONFIG_PACKET_MAX_LEN; + max_len = _odp_pool_glb->config.pkt_max_len; if (params->pkt.len && params->pkt.len < CONFIG_PACKET_MAX_SEG_LEN) @@ -1256,7 +1270,7 @@ int odp_pool_capability(odp_pool_capability_t *capa) /* Packet pools */ capa->pkt.max_pools = max_pools; - capa->pkt.max_len = CONFIG_PACKET_MAX_LEN; + capa->pkt.max_len = _odp_pool_glb->config.pkt_max_len; capa->pkt.max_num = _odp_pool_glb->config.pkt_max_num; capa->pkt.max_align = _odp_pool_glb->config.pkt_base_align; capa->pkt.min_headroom = CONFIG_PACKET_HEADROOM; diff --git a/platform/linux-generic/odp_system_info.c b/platform/linux-generic/odp_system_info.c index 638c756e8..cbbadf336 100644 --- a/platform/linux-generic/odp_system_info.c +++ b/platform/linux-generic/odp_system_info.c @@ -595,7 +595,6 @@ void odp_sys_config_print(void) ODP_PRINT("ODP_CONFIG_PKTIO_ENTRIES: %i\n", ODP_CONFIG_PKTIO_ENTRIES); ODP_PRINT("CONFIG_PACKET_HEADROOM: %i\n", CONFIG_PACKET_HEADROOM); ODP_PRINT("CONFIG_PACKET_TAILROOM: %i\n", CONFIG_PACKET_TAILROOM); - ODP_PRINT("CONFIG_PACKET_MAX_LEN: %i\n", CONFIG_PACKET_MAX_LEN); ODP_PRINT("ODP_CONFIG_SHM_BLOCKS: %i\n", ODP_CONFIG_SHM_BLOCKS); ODP_PRINT("CONFIG_BURST_SIZE: %i\n", CONFIG_BURST_SIZE); ODP_PRINT("CONFIG_POOL_MAX_NUM: %i\n", CONFIG_POOL_MAX_NUM); diff --git a/platform/linux-generic/test/inline-timer.conf b/platform/linux-generic/test/inline-timer.conf index a7fec6a98..096aab055 100644 --- a/platform/linux-generic/test/inline-timer.conf +++ b/platform/linux-generic/test/inline-timer.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.13" +config_file_version = "0.1.14" timer: { # Enable inline timer implementation diff --git a/platform/linux-generic/test/packet_align.conf b/platform/linux-generic/test/packet_align.conf index 95ecaf413..24ed46b56 100644 --- a/platform/linux-generic/test/packet_align.conf +++ b/platform/linux-generic/test/packet_align.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.13" +config_file_version = "0.1.14" pool: { pkt: { diff --git a/platform/linux-generic/test/process-mode.conf b/platform/linux-generic/test/process-mode.conf index 7cbc176fd..8e18feb2c 100644 --- a/platform/linux-generic/test/process-mode.conf +++ b/platform/linux-generic/test/process-mode.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.13" +config_file_version = "0.1.14" # Shared memory options shm: { -- cgit v1.2.3 From 9105edeac28718631a7bcb2f2938bda6511138a5 Mon Sep 17 00:00:00 2001 From: Nithin Dabilpuram Date: Mon, 30 Nov 2020 09:42:57 +0530 Subject: test: sched_pktio: cleanup prefetched events before worker exit For direct worker i.e worker with pipelining and timeouts disabled, cleanup prefetched events before worker exits. Also break before schedule multi is called if exit is triggered. Signed-off-by: Nithin Dabilpuram Reviewed-by: Janne Peltonen --- test/performance/odp_sched_pktio.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/test/performance/odp_sched_pktio.c b/test/performance/odp_sched_pktio.c index fc814c541..c752e2a91 100644 --- a/test/performance/odp_sched_pktio.c +++ b/test/performance/odp_sched_pktio.c @@ -203,9 +203,6 @@ static int worker_thread_direct(void *arg) odp_event_t ev[burst_size]; odp_packet_t pkt[burst_size]; - num_pkt = odp_schedule_multi(&queue, ODP_SCHED_NO_WAIT, - ev, burst_size); - polls++; if (polls == CHECK_PERIOD) { @@ -214,6 +211,9 @@ static int worker_thread_direct(void *arg) break; } + num_pkt = odp_schedule_multi(&queue, ODP_SCHED_NO_WAIT, + ev, burst_size); + if (num_pkt <= 0) continue; @@ -238,6 +238,22 @@ static int worker_thread_direct(void *arg) test_global->worker_stat[worker_id].rx_pkt += num_pkt; } + /* + * Free prefetched packets before exiting worker thread as + * such packets can block main thread event cleanup or + * cause buffer leak. + */ + odp_schedule_pause(); + while (1) { + odp_event_t ev; + + ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT); + if (ev == ODP_EVENT_INVALID) + break; + odp_event_free(ev); + } + + /* Non-prefetched events in scheduler are cleaned up by main thread */ printf("Worker %i stopped\n", worker_id); return 0; -- cgit v1.2.3 From 9670b8cc6b0f593a47a1abeafe0ee911ba13730d Mon Sep 17 00:00:00 2001 From: Fredrik Lindgren Date: Thu, 7 Jan 2021 09:31:03 +0100 Subject: linux-gen: ipsec: fix handling of sa_idx with multiple packets Fix table index handling for SA parameters in IPsec input and output API functions to prevent out-of-bound array access and to have each packet processed using the right SA when multiple packets are provided. Fixes: https://github.com/OpenDataPlane/odp/issues/1152 Signed-off-by: Fredrik Lindgren Reviewed-by: Janne Peltonen --- platform/linux-generic/odp_ipsec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/linux-generic/odp_ipsec.c b/platform/linux-generic/odp_ipsec.c index 37763d030..f0bbaf167 100644 --- a/platform/linux-generic/odp_ipsec.c +++ b/platform/linux-generic/odp_ipsec.c @@ -1675,7 +1675,7 @@ int odp_ipsec_in(const odp_packet_t pkt_in[], int num_in, if (0 == param->num_sa) { sa = ODP_IPSEC_SA_INVALID; } else { - sa = param->sa[sa_idx++]; + sa = param->sa[sa_idx]; ODP_ASSERT(ODP_IPSEC_SA_INVALID != sa); } @@ -1731,7 +1731,7 @@ int odp_ipsec_out(const odp_packet_t pkt_in[], int num_in, memset(&status, 0, sizeof(status)); - sa = param->sa[sa_idx++]; + sa = param->sa[sa_idx]; ODP_ASSERT(ODP_IPSEC_SA_INVALID != sa); if (0 == param->num_opt) @@ -1783,7 +1783,7 @@ int odp_ipsec_in_enq(const odp_packet_t pkt_in[], int num_in, if (0 == param->num_sa) { sa = ODP_IPSEC_SA_INVALID; } else { - sa = param->sa[sa_idx++]; + sa = param->sa[sa_idx]; ODP_ASSERT(ODP_IPSEC_SA_INVALID != sa); } @@ -1838,7 +1838,7 @@ int odp_ipsec_out_enq(const odp_packet_t pkt_in[], int num_in, memset(&status, 0, sizeof(status)); - sa = param->sa[sa_idx++]; + sa = param->sa[sa_idx]; ODP_ASSERT(ODP_IPSEC_SA_INVALID != sa); if (0 == param->num_opt) @@ -1942,7 +1942,7 @@ int odp_ipsec_out_inline(const odp_packet_t pkt_in[], int num_in, if (0 == param->num_sa) { sa = ODP_IPSEC_SA_INVALID; } else { - sa = param->sa[sa_idx++]; + sa = param->sa[sa_idx]; ODP_ASSERT(ODP_IPSEC_SA_INVALID != sa); } -- cgit v1.2.3 From 14748c2225bbaffce398a1031f30ccfd1ab78de5 Mon Sep 17 00:00:00 2001 From: Gowrishankar Muthukrishnan Date: Tue, 8 Dec 2020 11:07:06 +0530 Subject: validation: system: update hw isa checks for arm Update validation test for system info to check ISA versions for ARM HW. Signed-off-by: Gowrishankar Muthukrishnan Reviewed-by: Matias Elo --- test/validation/api/system/system.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/validation/api/system/system.c b/test/validation/api/system/system.c index 166872221..d00f09f28 100644 --- a/test/validation/api/system/system.c +++ b/test/validation/api/system/system.c @@ -517,9 +517,35 @@ static void system_test_info(void) printf(" ODP_CPU_ARCH_ARMV8_5\n"); else if (info.cpu_isa_sw.arm == ODP_CPU_ARCH_ARMV8_6) printf(" ODP_CPU_ARCH_ARMV8_6\n"); + else + CU_FAIL("Unknown CPU ISA SW ARCH found!"); if (info.cpu_isa_hw.arm != ODP_CPU_ARCH_ARM_UNKNOWN) CU_ASSERT(info.cpu_isa_sw.arm <= info.cpu_isa_hw.arm); + + if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV6) + printf(" ODP_CPU_ARCH_ARMV6\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV7) + printf(" ODP_CPU_ARCH_ARMV7\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV8_0) + printf(" ODP_CPU_ARCH_ARMV8_0\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV8_1) + printf(" ODP_CPU_ARCH_ARMV8_1\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV8_2) + printf(" ODP_CPU_ARCH_ARMV8_2\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV8_3) + printf(" ODP_CPU_ARCH_ARMV8_3\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV8_4) + printf(" ODP_CPU_ARCH_ARMV8_4\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV8_5) + printf(" ODP_CPU_ARCH_ARMV8_5\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARMV8_6) + printf(" ODP_CPU_ARCH_ARMV8_6\n"); + else if (info.cpu_isa_hw.arm == ODP_CPU_ARCH_ARM_UNKNOWN) + printf(" ODP_CPU_ARCH_ARM_UNKNOWN\n"); + else + CU_FAIL("Unknown CPU ISA HW ARCH found!"); + } } -- cgit v1.2.3 From b3f0a5b04a26cbcd15bc8c147958e409fc1d768e Mon Sep 17 00:00:00 2001 From: Satha Rao Date: Fri, 18 Dec 2020 09:02:55 -0500 Subject: test: l2fwd: add arguments to get packet length and segment length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Present l2fwd consider packet length 1536 for pool creation, it limits the packet length to X * 1536 when platform supports X number of segments. This new command line argument along with pool capabilities will create packet pool to support packets up to 64K MTU. Also added one more argument to get segment length, if requested segment length not sufficient to support packet length then segment length will be adjusted based on packet length and number of segments supported. Signed-off-by: Satha Rao Reviewed-by: Jere Leppänen --- test/performance/odp_l2fwd.c | 46 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/test/performance/odp_l2fwd.c b/test/performance/odp_l2fwd.c index 7cbc2cfab..ca8502ef7 100644 --- a/test/performance/odp_l2fwd.c +++ b/test/performance/odp_l2fwd.c @@ -105,6 +105,8 @@ typedef struct { uint64_t vec_tmo_ns; /* Vector formation timeout in ns */ uint32_t vec_size; /* Vector size */ int verbose; /* Verbose output */ + uint32_t packet_len; /* Maximum packet length supported */ + uint32_t seg_len; /* Pool segment length */ int promisc_mode; /* Promiscuous mode enabled */ } appl_args_t; @@ -1507,10 +1509,13 @@ static void usage(char *progname) " -x, --vec_size Vector size (default %i).\n" " -z, --vec_tmo_ns Vector timeout in ns (default %llu ns).\n" " -P, --promisc_mode Enable promiscuous mode.\n" + " -l, --packet_len Maximum length of packets supported (default %d).\n" + " -L, --seg_len Packet pool segment length\n" + " (default equal to packet length).\n" " -v, --verbose Verbose output.\n" " -h, --help Display help and exit.\n\n" "\n", NO_PATH(progname), NO_PATH(progname), MAX_PKTIOS, DEFAULT_VEC_SIZE, - DEFAULT_VEC_TMO + DEFAULT_VEC_TMO, POOL_PKT_LEN ); } @@ -1551,12 +1556,14 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) {"vec_tmo_ns", required_argument, NULL, 'z'}, {"vector_mode", no_argument, NULL, 'u'}, {"promisc_mode", no_argument, NULL, 'P'}, + {"packet_len", required_argument, NULL, 'l'}, + {"seg_len", required_argument, NULL, 'L'}, {"verbose", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; - static const char *shortopts = "+c:t:a:i:m:o:r:d:s:e:k:g:b:p:y:n:w:x:z:uPvh"; + static const char *shortopts = "+c:t:a:i:m:o:r:d:s:e:k:g:b:p:y:n:l:L:w:x:z:uPvh"; appl_args->time = 0; /* loop forever if time to run is 0 */ appl_args->accuracy = 1; /* get and print pps stats second */ @@ -1571,6 +1578,8 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) appl_args->chksum = 0; /* don't use checksum offload by default */ appl_args->pool_per_if = 0; appl_args->num_pkt = 0; + appl_args->packet_len = POOL_PKT_LEN; + appl_args->seg_len = UINT32_MAX; appl_args->promisc_mode = 0; appl_args->vector_mode = 0; appl_args->num_vec = 0; @@ -1716,6 +1725,12 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args) case 'n': appl_args->num_pkt = atoi(optarg); break; + case 'l': + appl_args->packet_len = atoi(optarg); + break; + case 'L': + appl_args->seg_len = atoi(optarg); + break; case 'P': appl_args->promisc_mode = 1; break; @@ -1928,7 +1943,7 @@ int main(int argc, char *argv[]) odp_pool_t pool, vec_pool; odp_init_t init; odp_pool_capability_t pool_capa; - uint32_t pkt_len, num_pkt; + uint32_t pkt_len, num_pkt, seg_len; /* Let helper collect its own arguments (e.g. --odph_proc) */ argc = odph_parse_options(argc, argv); @@ -2035,13 +2050,33 @@ int main(int argc, char *argv[]) return -1; } - pkt_len = POOL_PKT_LEN; + pkt_len = gbl_args->appl.packet_len; if (pool_capa.pkt.max_len && pkt_len > pool_capa.pkt.max_len) { pkt_len = pool_capa.pkt.max_len; printf("\nWarning: packet length reduced to %u\n\n", pkt_len); } + if (gbl_args->appl.seg_len == UINT32_MAX) + seg_len = gbl_args->appl.packet_len; + else + seg_len = gbl_args->appl.seg_len; + + /* Check whether we have sufficient segments to support requested packet + * length, if not adjust to bigger segment size */ + if (seg_len < (pkt_len / pool_capa.pkt.max_segs_per_pkt)) + seg_len = pkt_len / pool_capa.pkt.max_segs_per_pkt; + + if (pool_capa.pkt.min_seg_len && seg_len < pool_capa.pkt.min_seg_len) + seg_len = pool_capa.pkt.min_seg_len; + + if (pool_capa.pkt.max_seg_len && seg_len > pool_capa.pkt.max_seg_len) + seg_len = pool_capa.pkt.max_seg_len; + + if ((gbl_args->appl.seg_len != UINT32_MAX) && (seg_len != gbl_args->appl.seg_len)) + printf("\nWarning: Segment length requested %d configured %d\n", + gbl_args->appl.seg_len, seg_len); + /* zero means default number of packets */ if (gbl_args->appl.num_pkt == 0) num_pkt = DEFAULT_NUM_PKT; @@ -2062,11 +2097,12 @@ int main(int argc, char *argv[]) printf("Packets per pool: %u\n", num_pkt); printf("Packet length: %u\n", pkt_len); + printf("Segment length: %u\n", seg_len); printf("\n\n"); /* Create packet pool */ odp_pool_param_init(¶ms); - params.pkt.seg_len = pkt_len; + params.pkt.seg_len = seg_len; params.pkt.len = pkt_len; params.pkt.num = num_pkt; params.type = ODP_POOL_PACKET; -- cgit v1.2.3 From 963e485687025effa3a7619d1fae5d0817c3e6fe Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Tue, 19 Jan 2021 17:25:06 +0200 Subject: test: mem_perf: add memory performance test Added new test application that measures memory system bandwidth. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo Reviewed-by: Jerin Jacob --- test/performance/.gitignore | 1 + test/performance/Makefile.am | 2 + test/performance/odp_mem_perf.c | 445 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 448 insertions(+) create mode 100644 test/performance/odp_mem_perf.c diff --git a/test/performance/.gitignore b/test/performance/.gitignore index a4e78b9af..80396e5d9 100644 --- a/test/performance/.gitignore +++ b/test/performance/.gitignore @@ -6,6 +6,7 @@ odp_cpu_bench odp_crypto odp_ipsec odp_l2fwd +odp_mem_perf odp_packet_gen odp_pktio_ordered odp_pktio_perf diff --git a/test/performance/Makefile.am b/test/performance/Makefile.am index 4696b2c5e..624795f8b 100644 --- a/test/performance/Makefile.am +++ b/test/performance/Makefile.am @@ -6,6 +6,7 @@ EXECUTABLES = odp_bench_packet \ odp_cpu_bench \ odp_crypto \ odp_ipsec \ + odp_mem_perf \ odp_pktio_perf \ odp_pool_perf \ odp_queue_perf \ @@ -42,6 +43,7 @@ odp_bench_packet_SOURCES = odp_bench_packet.c odp_cpu_bench_SOURCES = odp_cpu_bench.c odp_crypto_SOURCES = odp_crypto.c odp_ipsec_SOURCES = odp_ipsec.c +odp_mem_perf_SOURCES = odp_mem_perf.c odp_packet_gen_SOURCES = odp_packet_gen.c odp_pktio_ordered_SOURCES = odp_pktio_ordered.c dummy_crc.h odp_sched_latency_SOURCES = odp_sched_latency.c diff --git a/test/performance/odp_mem_perf.c b/test/performance/odp_mem_perf.c new file mode 100644 index 000000000..a833a04e8 --- /dev/null +++ b/test/performance/odp_mem_perf.c @@ -0,0 +1,445 @@ +/* Copyright (c) 2021, Nokia + * + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef struct test_options_t { + uint32_t num_cpu; + uint32_t num_round; + uint64_t data_len; + uint32_t shm_flags; + int private; + int mode; + +} test_options_t; + +typedef struct test_global_t test_global_t; + +typedef struct test_thread_ctx_t { + test_global_t *global; + void *shm_addr; + uint64_t nsec; + +} test_thread_ctx_t; + +struct test_global_t { + test_options_t test_options; + + odp_barrier_t barrier; + uint32_t num_shm; + odp_shm_t shm[ODP_THREAD_COUNT_MAX]; + void *shm_addr[ODP_THREAD_COUNT_MAX]; + odp_cpumask_t cpumask; + odph_thread_t thread_tbl[ODP_THREAD_COUNT_MAX]; + test_thread_ctx_t thread_ctx[ODP_THREAD_COUNT_MAX]; + +}; + +static test_global_t test_global; + +static void print_usage(void) +{ + printf("\n" + "Memory performance test\n" + "\n" + "Usage: odp_mem_perf [options]\n" + "\n" + " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs. Default 1.\n" + " -r, --num_round Number of rounds\n" + " -l, --data_len Data length in bytes\n" + " -f, --flags SHM flags parameter. Default 0.\n" + " -p, --private 0: The same memory area is shared between threads (default)\n" + " 1: Memory areas are private to each thread. This increases\n" + " memory consumption to num_cpu * data_len.\n" + " -m, --mode 0: Memset data (default)\n" + " 1: Memcpy data. On each round, reads data from one half of the memory area\n" + " and writes it to the other half.\n" + " -h, --help This help\n" + "\n"); +} + +static int parse_options(int argc, char *argv[], test_options_t *test_options) +{ + int opt; + int long_index; + int ret = 0; + + static const struct option longopts[] = { + {"num_cpu", required_argument, NULL, 'c'}, + {"num_round", required_argument, NULL, 'r'}, + {"data_len", required_argument, NULL, 'l'}, + {"flags", required_argument, NULL, 'f'}, + {"private", required_argument, NULL, 'p'}, + {"mode", required_argument, NULL, 'm'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + static const char *shortopts = "+c:r:l:f:p:m:h"; + + test_options->num_cpu = 1; + test_options->num_round = 1000; + test_options->data_len = 10 * 1024 * 1024; + test_options->shm_flags = 0; + test_options->private = 0; + test_options->mode = 0; + + while (1) { + opt = getopt_long(argc, argv, shortopts, longopts, &long_index); + + if (opt == -1) + break; + + switch (opt) { + case 'c': + test_options->num_cpu = atoi(optarg); + break; + case 'r': + test_options->num_round = atoi(optarg); + break; + case 'l': + test_options->data_len = strtoull(optarg, NULL, 0); + break; + case 'f': + test_options->shm_flags = strtoul(optarg, NULL, 0); + break; + case 'p': + test_options->private = atoi(optarg); + break; + case 'm': + test_options->mode = atoi(optarg); + break; + case 'h': + /* fall through */ + default: + print_usage(); + ret = -1; + break; + } + } + + return ret; +} + +static int set_num_cpu(test_global_t *global) +{ + int ret; + test_options_t *test_options = &global->test_options; + int num_cpu = test_options->num_cpu; + + /* One thread used for the main thread */ + if (num_cpu > ODP_THREAD_COUNT_MAX - 1) { + ODPH_ERR("Too many workers. Maximum is %i.\n", ODP_THREAD_COUNT_MAX - 1); + return -1; + } + + ret = odp_cpumask_default_worker(&global->cpumask, num_cpu); + + if (num_cpu && ret != num_cpu) { + ODPH_ERR("Too many workers. Max supported %i.\n", ret); + return -1; + } + + /* Zero: all available workers */ + if (num_cpu == 0) { + num_cpu = ret; + test_options->num_cpu = num_cpu; + } + + odp_barrier_init(&global->barrier, num_cpu); + + return 0; +} + +static int create_shm(test_global_t *global) +{ + odp_shm_capability_t shm_capa; + odp_shm_t shm; + void *addr; + uint32_t i, num_shm; + test_options_t *test_options = &global->test_options; + uint32_t num_round = test_options->num_round; + uint32_t num_cpu = test_options->num_cpu; + uint64_t data_len = test_options->data_len; + uint32_t shm_flags = test_options->shm_flags; + int private = test_options->private; + char name[] = "mem_perf_00"; + + num_shm = 1; + if (private) + num_shm = num_cpu; + + printf("\nMemory performance test\n"); + printf(" num cpu %u\n", num_cpu); + printf(" num rounds %u\n", num_round); + printf(" data len %" PRIu64 "\n", data_len); + printf(" memory footprint %" PRIu64 "\n", num_shm * data_len); + printf(" shm flags 0x%x\n", shm_flags); + printf(" num shm %u\n", num_shm); + printf(" private %i\n", private); + printf(" mode %i\n", test_options->mode); + + if (odp_shm_capability(&shm_capa)) { + ODPH_ERR("SHM capa failed.\n"); + return -1; + } + + if (shm_capa.max_size && data_len > shm_capa.max_size) { + ODPH_ERR("Data len too large. Maximum len is %" PRIu64 "\n", shm_capa.max_size); + return -1; + } + + if (num_shm > shm_capa.max_blocks) { + ODPH_ERR("Too many SHM blocks. Maximum is %u\n", shm_capa.max_blocks); + return -1; + } + + for (i = 0; i < num_shm; i++) { + name[9] = '0' + i / 10; + name[10] = '0' + i % 10; + + shm = odp_shm_reserve(name, data_len, ODP_CACHE_LINE_SIZE, shm_flags); + + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("SHM[%u] reserve failed.\n", i); + return -1; + } + + global->shm[i] = shm; + + addr = odp_shm_addr(shm); + if (addr == NULL) { + ODPH_ERR("SHM[%u] addr failed.\n", i); + return -1; + } + + global->shm_addr[i] = addr; + + printf(" shm addr[%u] %p\n", i, addr); + } + + printf("\n"); + global->num_shm = num_shm; + + odp_shm_print_all(); + + return 0; +} + +static int free_shm(test_global_t *global) +{ + uint32_t i; + + for (i = 0; i < global->num_shm; i++) { + if (odp_shm_free(global->shm[i])) { + ODPH_ERR("SHM[%u] free failed.\n", i); + return -1; + } + } + + return 0; +} + +static int run_test(void *arg) +{ + int thr; + uint32_t i; + uint64_t nsec; + odp_time_t t1, t2; + test_thread_ctx_t *thread_ctx = arg; + test_global_t *global = thread_ctx->global; + test_options_t *test_options = &global->test_options; + uint32_t num_round = test_options->num_round; + uint64_t data_len = test_options->data_len; + uint64_t half_len = data_len / 2; + int mode = test_options->mode; + uint8_t *addr = thread_ctx->shm_addr; + + thr = odp_thread_id(); + + /* Start all workers at the same time */ + odp_barrier_wait(&global->barrier); + + t1 = odp_time_local(); + + if (mode == 0) { + for (i = 0; i < num_round; i++) + memset(addr, thr + i, data_len); + } else { + for (i = 0; i < num_round; i++) { + if ((i & 0x1) == 0) + memcpy(&addr[half_len], addr, half_len); + else + memcpy(addr, &addr[half_len], half_len); + } + } + + t2 = odp_time_local(); + + nsec = odp_time_diff_ns(t2, t1); + + /* Update stats */ + thread_ctx->nsec = nsec; + + return 0; +} + +static int start_workers(test_global_t *global, odp_instance_t instance) +{ + odph_thread_common_param_t param; + int i, ret; + test_options_t *test_options = &global->test_options; + int num_cpu = test_options->num_cpu; + odph_thread_param_t thr_param[num_cpu]; + + memset(¶m, 0, sizeof(odph_thread_common_param_t)); + param.instance = instance; + param.cpumask = &global->cpumask; + + memset(thr_param, 0, sizeof(thr_param)); + for (i = 0; i < num_cpu; i++) { + test_thread_ctx_t *thread_ctx = &global->thread_ctx[i]; + + thread_ctx->global = global; + thread_ctx->shm_addr = global->shm_addr[0]; + if (global->test_options.private) + thread_ctx->shm_addr = global->shm_addr[i]; + + thr_param[i].thr_type = ODP_THREAD_WORKER; + thr_param[i].start = run_test; + thr_param[i].arg = thread_ctx; + } + + ret = odph_thread_create(global->thread_tbl, ¶m, thr_param, num_cpu); + if (ret != num_cpu) { + ODPH_ERR("Failed to create all threads %i\n", ret); + return -1; + } + + return 0; +} + +static void print_stat(test_global_t *global) +{ + int i, num; + double nsec_ave; + uint64_t data_touch; + test_options_t *test_options = &global->test_options; + int num_cpu = test_options->num_cpu; + uint32_t num_round = test_options->num_round; + uint64_t data_len = test_options->data_len; + uint64_t nsec_sum = 0; + + for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) + nsec_sum += global->thread_ctx[i].nsec; + + if (nsec_sum == 0) { + printf("No results.\n"); + return; + } + + data_touch = num_round * data_len; + nsec_ave = nsec_sum / num_cpu; + num = 0; + + printf("RESULTS - per thread (MB per sec):\n"); + printf("----------------------------------\n"); + printf(" 1 2 3 4 5 6 7 8 9 10"); + + for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) { + if (global->thread_ctx[i].nsec) { + if ((num % 10) == 0) + printf("\n "); + + printf("%8.1f ", data_touch / (global->thread_ctx[i].nsec / 1000.0)); + num++; + } + } + printf("\n\n"); + + printf("RESULTS - average over %i threads:\n", num_cpu); + printf("----------------------------------\n"); + printf(" duration: %.6f sec\n", nsec_ave / 1000000000); + printf(" bandwidth per cpu: %.3f MB/s\n", data_touch / (nsec_ave / 1000.0)); + printf(" total bandwidth: %.3f MB/s\n", (num_cpu * data_touch) / (nsec_ave / 1000.0)); + printf("\n"); +} + +int main(int argc, char **argv) +{ + odp_instance_t instance; + odp_init_t init; + test_global_t *global; + + global = &test_global; + memset(global, 0, sizeof(test_global_t)); + + if (parse_options(argc, argv, &global->test_options)) + return -1; + + /* List features not to be used */ + odp_init_param_init(&init); + init.not_used.feat.cls = 1; + init.not_used.feat.compress = 1; + init.not_used.feat.crypto = 1; + init.not_used.feat.ipsec = 1; + init.not_used.feat.schedule = 1; + init.not_used.feat.timer = 1; + init.not_used.feat.tm = 1; + + /* Init ODP before calling anything else */ + if (odp_init_global(&instance, &init, NULL)) { + ODPH_ERR("Global init failed.\n"); + return -1; + } + + /* Init this thread */ + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + ODPH_ERR("Local init failed.\n"); + return -1; + } + + odp_sys_info_print(); + + if (set_num_cpu(global)) + return -1; + + if (create_shm(global)) + return -1; + + /* Start workers */ + if (start_workers(global, instance)) + return -1; + + /* Wait workers to exit */ + odph_thread_join(global->thread_tbl, global->test_options.num_cpu); + + print_stat(global); + + if (free_shm(global)) + return -1; + + if (odp_term_local()) { + ODPH_ERR("term local failed.\n"); + return -1; + } + + if (odp_term_global(instance)) { + ODPH_ERR("term global failed.\n"); + return -1; + } + + return 0; +} -- cgit v1.2.3 From d07a44c6ed222746d661f3c6b91d3c7f3b5f799b Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 20 Jan 2021 16:06:48 -0600 Subject: linux-gen: hash: prepare for arch specific implementations Refactor build system to enable adding architecture specific hash function implementations. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/Makefile.am | 28 +- .../arch/default/odp/api/abi/hash_crc32.h | 37 ++ .../linux-generic/arch/default/odp_hash_crc32.c | 496 +++++++++++++++++++++ .../linux-generic/include-abi/odp/api/abi/hash.h | 3 + .../include/odp/api/plat/hash_inlines.h | 47 ++ platform/linux-generic/odp_hash_api.c | 11 + platform/linux-generic/odp_hash_crc32.c | 92 ---- platform/linux-generic/odp_hash_crc32c.c | 407 ----------------- 8 files changed, 614 insertions(+), 507 deletions(-) create mode 100644 platform/linux-generic/arch/default/odp/api/abi/hash_crc32.h create mode 100644 platform/linux-generic/arch/default/odp_hash_crc32.c create mode 100644 platform/linux-generic/include/odp/api/plat/hash_inlines.h create mode 100644 platform/linux-generic/odp_hash_api.c delete mode 100644 platform/linux-generic/odp_hash_crc32.c delete mode 100644 platform/linux-generic/odp_hash_crc32c.c diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 66fbf3364..645022dd6 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -34,6 +34,7 @@ odpapiplatinclude_HEADERS = \ include/odp/api/plat/cpu_inlines.h \ include/odp/api/plat/event_inlines.h \ include/odp/api/plat/event_vector_inline_types.h \ + include/odp/api/plat/hash_inlines.h \ include/odp/api/plat/packet_flag_inlines.h \ include/odp/api/plat/packet_inline_types.h \ include/odp/api/plat/packet_inlines.h \ @@ -173,8 +174,6 @@ __LIB__libodp_linux_la_SOURCES = \ odp_errno.c \ odp_event.c \ odp_fdserver.c \ - odp_hash_crc32.c \ - odp_hash_crc32c.c \ odp_hash_crc_gen.c \ odp_impl.c \ odp_init.c \ @@ -253,6 +252,7 @@ __LIB__libodp_linux_la_SOURCES += \ odp_byteorder_api.c \ odp_cpu_api.c \ odp_event_api.c \ + odp_hash_api.c \ odp_packet_api.c \ odp_packet_flags_api.c \ odp_pktio_api.c \ @@ -267,9 +267,11 @@ endif if ARCH_IS_ARM __LIB__libodp_linux_la_SOURCES += arch/default/odp_cpu_cycles.c \ arch/default/odp_global_time.c \ + arch/default/odp_hash_crc32.c \ arch/arm/odp_sysinfo_parse.c odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ - arch/default/odp/api/abi/cpu_time.h + arch/default/odp/api/abi/cpu_time.h \ + arch/default/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/arm/odp/api/abi/cpu.h endif @@ -281,9 +283,11 @@ endif if ARCH_IS_AARCH64 __LIB__libodp_linux_la_SOURCES += arch/default/odp_cpu_cycles.c \ arch/aarch64/odp_global_time.c \ + arch/default/odp_hash_crc32.c \ arch/aarch64/odp_sysinfo_parse.c odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ - arch/default/odp/api/abi/cpu_time.h + arch/default/odp/api/abi/cpu_time.h \ + arch/default/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/aarch64/odp/api/abi/cpu.h endif @@ -295,9 +299,11 @@ endif if ARCH_IS_DEFAULT __LIB__libodp_linux_la_SOURCES += arch/default/odp_cpu_cycles.c \ arch/default/odp_global_time.c \ + arch/default/odp_hash_crc32.c \ arch/default/odp_sysinfo_parse.c odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ - arch/default/odp/api/abi/cpu_time.h + arch/default/odp/api/abi/cpu_time.h \ + arch/default/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu.h endif @@ -307,9 +313,11 @@ endif if ARCH_IS_MIPS64 __LIB__libodp_linux_la_SOURCES += arch/mips64/odp_cpu_cycles.c \ arch/default/odp_global_time.c \ + arch/default/odp_hash_crc32.c \ arch/mips64/odp_sysinfo_parse.c odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ - arch/default/odp/api/abi/cpu_time.h + arch/default/odp/api/abi/cpu_time.h \ + arch/default/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/mips64/odp/api/abi/cpu.h endif @@ -319,9 +327,11 @@ endif if ARCH_IS_POWERPC __LIB__libodp_linux_la_SOURCES += arch/default/odp_cpu_cycles.c \ arch/default/odp_global_time.c \ + arch/default/odp_hash_crc32.c \ arch/powerpc/odp_sysinfo_parse.c odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ - arch/default/odp/api/abi/cpu_time.h + arch/default/odp/api/abi/cpu_time.h \ + arch/default/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/powerpc/odp/api/abi/cpu.h endif @@ -332,10 +342,12 @@ if ARCH_IS_X86 __LIB__libodp_linux_la_SOURCES += arch/x86/cpu_flags.c \ arch/x86/odp_cpu_cycles.c \ arch/x86/odp_global_time.c \ + arch/default/odp_hash_crc32.c \ arch/x86/odp_sysinfo_parse.c odpapiabiarchinclude_HEADERS += arch/x86/odp/api/abi/cpu_inlines.h \ arch/x86/odp/api/abi/cpu_rdtsc.h \ - arch/x86/odp/api/abi/cpu_time.h + arch/x86/odp/api/abi/cpu_time.h \ + arch/default/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/x86/odp/api/abi/cpu.h endif diff --git a/platform/linux-generic/arch/default/odp/api/abi/hash_crc32.h b/platform/linux-generic/arch/default/odp/api/abi/hash_crc32.h new file mode 100644 index 000000000..8759ed948 --- /dev/null +++ b/platform/linux-generic/arch/default/odp/api/abi/hash_crc32.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_API_ABI_HASH_CRC32_H_ +#define ODP_API_ABI_HASH_CRC32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +uint32_t _odp_hash_crc32_generic(const void *data, uint32_t data_len, + uint32_t init_val); +uint32_t _odp_hash_crc32c_generic(const void *data, uint32_t data_len, + uint32_t init_val); + +static inline uint32_t _odp_hash_crc32(const void *data, uint32_t data_len, + uint32_t init_val) +{ + return _odp_hash_crc32_generic(data, data_len, init_val); +} + +static inline uint32_t _odp_hash_crc32c(const void *data, uint32_t data_len, + uint32_t init_val) +{ + return _odp_hash_crc32c_generic(data, data_len, init_val); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-generic/arch/default/odp_hash_crc32.c b/platform/linux-generic/arch/default/odp_hash_crc32.c new file mode 100644 index 000000000..f71c11909 --- /dev/null +++ b/platform/linux-generic/arch/default/odp_hash_crc32.c @@ -0,0 +1,496 @@ +/* Copyright (c) 2015-2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include + +#include +#include + +/* Table generated with odp_hash_crc_gen64() */ +static const uint32_t crc32_table[256] ODP_ALIGNED_CACHE = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +static const uint32_t crc32c_tables[8][256] = {{ + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 +}, +{ + 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, + 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, + 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, + 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, + 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, + 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, + 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, + 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, + 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, + 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, + 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, + 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, + 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, + 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, + 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, + 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, + 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, + 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, + 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, + 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, + 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, + 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, + 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, + 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, + 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, + 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, + 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, + 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, + 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, + 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, + 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, + 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 +}, +{ + 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, + 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, + 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, + 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, + 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, + 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, + 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, + 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, + 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, + 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, + 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, + 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, + 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, + 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, + 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, + 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, + 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, + 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, + 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, + 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, + 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, + 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, + 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, + 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, + 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, + 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, + 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, + 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, + 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, + 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, + 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, + 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 +}, +{ + 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, + 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, + 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, + 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, + 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, + 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, + 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, + 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, + 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, + 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, + 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, + 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, + 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, + 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, + 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, + 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, + 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, + 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, + 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, + 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, + 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, + 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, + 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, + 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, + 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, + 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, + 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, + 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, + 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, + 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, + 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, + 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 +}, +{ + 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, + 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, + 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, + 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, + 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, + 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, + 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, + 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, + 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, + 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, + 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, + 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, + 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, + 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, + 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, + 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, + 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, + 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, + 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, + 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, + 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, + 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, + 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, + 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, + 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, + 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, + 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, + 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, + 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, + 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, + 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, + 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 +}, +{ + 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, + 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, + 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, + 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, + 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, + 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, + 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, + 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, + 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, + 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, + 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, + 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, + 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, + 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, + 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, + 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, + 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, + 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, + 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, + 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, + 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, + 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, + 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, + 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, + 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, + 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, + 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, + 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, + 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, + 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, + 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, + 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C +}, +{ + 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, + 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, + 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, + 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, + 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, + 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, + 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, + 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, + 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, + 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, + 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, + 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, + 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, + 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, + 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, + 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, + 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, + 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, + 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, + 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, + 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, + 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, + 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, + 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, + 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, + 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, + 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, + 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, + 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, + 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, + 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, + 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F +}, +{ + 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, + 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, + 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, + 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, + 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, + 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, + 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, + 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, + 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, + 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, + 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, + 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, + 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, + 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, + 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, + 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, + 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, + 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, + 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, + 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, + 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, + 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, + 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, + 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, + 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, + 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, + 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, + 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, + 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, + 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, + 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, + 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 +} }; + +#define CRC32_UPD(crc, n) \ + (crc32c_tables[(n)][(crc) & 0xff] ^ \ + crc32c_tables[(n) - 1][((crc) >> 8) & 0xff]) + +static inline uint32_t crc32c_u8(uint8_t data, uint32_t init_val) +{ + uint32_t crc; + + crc = init_val; + crc ^= data; + + return crc32c_tables[0][crc & 0xff] ^ (crc >> 8); +} + +static inline uint32_t crc32c_u16(uint16_t data, uint32_t init_val) +{ + uint32_t crc; + + crc = init_val; + crc ^= data; + + crc = CRC32_UPD(crc, 1) ^ (crc >> 16); + + return crc; +} + +static inline uint32_t crc32c_u32(uint32_t data, uint32_t init_val) +{ + uint32_t crc, term1, term2; + + crc = init_val; + crc ^= data; + + term1 = CRC32_UPD(crc, 3); + term2 = crc >> 16; + crc = term1 ^ CRC32_UPD(term2, 1); + + return crc; +} + +static inline uint32_t crc32c_u64(uint64_t data, uint32_t init_val) +{ + uint32_t crc, term1, term2; + + union { + uint64_t u64; + uint32_t u32[2]; + } d; + + d.u64 = data; + + crc = init_val; + crc ^= d.u32[0]; + + term1 = CRC32_UPD(crc, 7); + term2 = crc >> 16; + crc = term1 ^ CRC32_UPD(term2, 5); + term1 = CRC32_UPD(d.u32[1], 3); + term2 = d.u32[1] >> 16; + crc ^= term1 ^ CRC32_UPD(term2, 1); + + return crc; +} + +#include + +uint32_t _odp_hash_crc32_generic(const void *data_ptr, uint32_t data_len, + uint32_t init_val) +{ + uint32_t i, crc; + const uint8_t *byte = data_ptr; + + crc = init_val; + + for (i = 0; i < data_len; i++) + crc = crc32_table[(crc ^ byte[i]) & 0xff] ^ (crc >> 8); + + return crc; +} + +uint32_t _odp_hash_crc32c_generic(const void *data, uint32_t data_len, + uint32_t init_val) +{ + uint32_t i; + uintptr_t pd = (uintptr_t)data; + + for (i = 0; i < data_len / 8; i++) { + init_val = crc32c_u64(*(const uint64_t *)pd, init_val); + pd += 8; + } + + if (data_len & 0x4) { + init_val = crc32c_u32(*(const uint32_t *)pd, init_val); + pd += 4; + } + + if (data_len & 0x2) { + init_val = crc32c_u16(*(const uint16_t *)pd, init_val); + pd += 2; + } + + if (data_len & 0x1) + init_val = crc32c_u8(*(const uint8_t *)pd, init_val); + + return init_val; +} + +#include diff --git a/platform/linux-generic/include-abi/odp/api/abi/hash.h b/platform/linux-generic/include-abi/odp/api/abi/hash.h index fc81dcc91..b132d7eb4 100644 --- a/platform/linux-generic/include-abi/odp/api/abi/hash.h +++ b/platform/linux-generic/include-abi/odp/api/abi/hash.h @@ -15,4 +15,7 @@ #include +/* Inlined functions for non-ABI compat mode */ +#include + #endif diff --git a/platform/linux-generic/include/odp/api/plat/hash_inlines.h b/platform/linux-generic/include/odp/api/plat/hash_inlines.h new file mode 100644 index 000000000..b38a34d53 --- /dev/null +++ b/platform/linux-generic/include/odp/api/plat/hash_inlines.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_PLAT_HASH_INLINES_H_ +#define ODP_PLAT_HASH_INLINES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/** @cond _ODP_HIDE_FROM_DOXYGEN_ */ + +#ifndef _ODP_NO_INLINE + /* Inline functions by default */ + #define _ODP_INLINE static inline + #define odp_hash_crc32 __odp_hash_crc32 + #define odp_hash_crc32c __odp_hash_crc32c +#else + #define _ODP_INLINE +#endif + +_ODP_INLINE uint32_t odp_hash_crc32(const void *data, uint32_t data_len, + uint32_t init_val) +{ + return _odp_hash_crc32(data, data_len, init_val); +} + +_ODP_INLINE uint32_t odp_hash_crc32c(const void *data, uint32_t data_len, + uint32_t init_val) +{ + return _odp_hash_crc32c(data, data_len, init_val); +} + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-generic/odp_hash_api.c b/platform/linux-generic/odp_hash_api.c new file mode 100644 index 000000000..893c9dc11 --- /dev/null +++ b/platform/linux-generic/odp_hash_api.c @@ -0,0 +1,11 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +/* Non-inlined functions for ABI compat mode */ +#define _ODP_NO_INLINE +#include diff --git a/platform/linux-generic/odp_hash_crc32.c b/platform/linux-generic/odp_hash_crc32.c deleted file mode 100644 index e1416d630..000000000 --- a/platform/linux-generic/odp_hash_crc32.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include - -#include -#include - -/* Table generated with odp_hash_crc_gen64() */ -static const uint32_t crc32_table[256] ODP_ALIGNED_CACHE = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -uint32_t odp_hash_crc32(const void *data_ptr, uint32_t data_len, - uint32_t init_val) -{ - uint32_t i, crc; - const uint8_t *byte = data_ptr; - - crc = init_val; - - for (i = 0; i < data_len; i++) - crc = crc32_table[(crc ^ byte[i]) & 0xff] ^ (crc >> 8); - - return crc; -} diff --git a/platform/linux-generic/odp_hash_crc32c.c b/platform/linux-generic/odp_hash_crc32c.c deleted file mode 100644 index 304b8e2a5..000000000 --- a/platform/linux-generic/odp_hash_crc32c.c +++ /dev/null @@ -1,407 +0,0 @@ -/* Copyright (c) 2015-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#include - -static const uint32_t crc32c_tables[8][256] = {{ - 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 -}, -{ - 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, - 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, - 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, - 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, - 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, - 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, - 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, - 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, - 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, - 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, - 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, - 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, - 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, - 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, - 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, - 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, - 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, - 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, - 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, - 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, - 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, - 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, - 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, - 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, - 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, - 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, - 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, - 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, - 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, - 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, - 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, - 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 -}, -{ - 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, - 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, - 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, - 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, - 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, - 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, - 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, - 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, - 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, - 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, - 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, - 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, - 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, - 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, - 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, - 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, - 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, - 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, - 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, - 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, - 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, - 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, - 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, - 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, - 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, - 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, - 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, - 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, - 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, - 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, - 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, - 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 -}, -{ - 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, - 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, - 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, - 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, - 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, - 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, - 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, - 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, - 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, - 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, - 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, - 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, - 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, - 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, - 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, - 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, - 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, - 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, - 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, - 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, - 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, - 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, - 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, - 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, - 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, - 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, - 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, - 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, - 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, - 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, - 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, - 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 -}, -{ - 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, - 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, - 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, - 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, - 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, - 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, - 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, - 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, - 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, - 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, - 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, - 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, - 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, - 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, - 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, - 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, - 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, - 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, - 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, - 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, - 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, - 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, - 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, - 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, - 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, - 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, - 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, - 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, - 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, - 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, - 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, - 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 -}, -{ - 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, - 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, - 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, - 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, - 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, - 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, - 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, - 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, - 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, - 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, - 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, - 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, - 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, - 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, - 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, - 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, - 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, - 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, - 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, - 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, - 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, - 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, - 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, - 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, - 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, - 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, - 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, - 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, - 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, - 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, - 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, - 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C -}, -{ - 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, - 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, - 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, - 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, - 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, - 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, - 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, - 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, - 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, - 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, - 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, - 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, - 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, - 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, - 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, - 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, - 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, - 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, - 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, - 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, - 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, - 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, - 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, - 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, - 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, - 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, - 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, - 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, - 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, - 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, - 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, - 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F -}, -{ - 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, - 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, - 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, - 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, - 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, - 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, - 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, - 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, - 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, - 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, - 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, - 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, - 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, - 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, - 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, - 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, - 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, - 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, - 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, - 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, - 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, - 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, - 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, - 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, - 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, - 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, - 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, - 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, - 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, - 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, - 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, - 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 -} }; - -#define CRC32_UPD(crc, n) \ - (crc32c_tables[(n)][(crc) & 0xff] ^ \ - crc32c_tables[(n) - 1][((crc) >> 8) & 0xff]) - -static inline uint32_t crc32c_u8(uint8_t data, uint32_t init_val) -{ - uint32_t crc; - - crc = init_val; - crc ^= data; - - return crc32c_tables[0][crc & 0xff] ^ (crc >> 8); -} - -static inline uint32_t crc32c_u16(uint16_t data, uint32_t init_val) -{ - uint32_t crc; - - crc = init_val; - crc ^= data; - - crc = CRC32_UPD(crc, 1) ^ (crc >> 16); - - return crc; -} - -static inline uint32_t crc32c_u32(uint32_t data, uint32_t init_val) -{ - uint32_t crc, term1, term2; - - crc = init_val; - crc ^= data; - - term1 = CRC32_UPD(crc, 3); - term2 = crc >> 16; - crc = term1 ^ CRC32_UPD(term2, 1); - - return crc; -} - -static inline uint32_t crc32c_u64(uint64_t data, uint32_t init_val) -{ - uint32_t crc, term1, term2; - - union { - uint64_t u64; - uint32_t u32[2]; - } d; - - d.u64 = data; - - crc = init_val; - crc ^= d.u32[0]; - - term1 = CRC32_UPD(crc, 7); - term2 = crc >> 16; - crc = term1 ^ CRC32_UPD(term2, 5); - term1 = CRC32_UPD(d.u32[1], 3); - term2 = d.u32[1] >> 16; - crc ^= term1 ^ CRC32_UPD(term2, 1); - - return crc; -} - -uint32_t odp_hash_crc32c(const void *data, uint32_t data_len, - uint32_t init_val) -{ - uint32_t i; - uintptr_t pd = (uintptr_t)data; - - for (i = 0; i < data_len / 8; i++) { - init_val = crc32c_u64(*(const uint64_t *)pd, init_val); - pd += 8; - } - - if (data_len & 0x4) { - init_val = crc32c_u32(*(const uint32_t *)pd, init_val); - pd += 4; - } - - if (data_len & 0x2) { - init_val = crc32c_u16(*(const uint16_t *)pd, init_val); - pd += 2; - } - - if (data_len & 0x1) - init_val = crc32c_u8(*(const uint8_t *)pd, init_val); - - return init_val; -} -- cgit v1.2.3 From df3abb351d23fbd4a738e43ab0f6b25de7230679 Mon Sep 17 00:00:00 2001 From: Malvika Gupta Date: Wed, 20 Jan 2021 16:13:23 -0600 Subject: linux-gen: hash: add armv8-a crc32 hash functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Armv8-A architecture-specific CRC32 and CRC32C extensions. Signed-off-by: Malvika Gupta Signed-off-by: Matias Elo Reviewed-by: Govindarajan Mohandoss Reviewed-by: Jere Leppänen Reviewed-by: Petri Savolainen --- platform/linux-generic/Makefile.am | 2 +- .../arch/aarch64/odp/api/abi/hash_crc32.h | 103 +++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 platform/linux-generic/arch/aarch64/odp/api/abi/hash_crc32.h diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 645022dd6..70ab7ab7c 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -287,7 +287,7 @@ __LIB__libodp_linux_la_SOURCES += arch/default/odp_cpu_cycles.c \ arch/aarch64/odp_sysinfo_parse.c odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ arch/default/odp/api/abi/cpu_time.h \ - arch/default/odp/api/abi/hash_crc32.h + arch/aarch64/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/aarch64/odp/api/abi/cpu.h endif diff --git a/platform/linux-generic/arch/aarch64/odp/api/abi/hash_crc32.h b/platform/linux-generic/arch/aarch64/odp/api/abi/hash_crc32.h new file mode 100644 index 000000000..fd7bf91c6 --- /dev/null +++ b/platform/linux-generic/arch/aarch64/odp/api/abi/hash_crc32.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2021 ARM Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_API_ABI_HASH_CRC32_H_ +#define ODP_API_ABI_HASH_CRC32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +uint32_t _odp_hash_crc32_generic(const void *data, uint32_t data_len, + uint32_t init_val); +uint32_t _odp_hash_crc32c_generic(const void *data, uint32_t data_len, + uint32_t init_val); + +#ifdef __ARM_FEATURE_CRC32 + +#include + +static inline uint32_t _odp_hash_crc32(const void *data_ptr, uint32_t data_len, + uint32_t init_val) +{ + uint32_t i; + uintptr_t pd = (uintptr_t)data_ptr; + + for (i = 0; i < data_len / 8; i++) { + init_val = __crc32d(init_val, *(const uint64_t *)pd); + pd += 8; + } + + if (data_len & 0x4) { + init_val = __crc32w(init_val, *(const uint32_t *)pd); + pd += 4; + } + + if (data_len & 0x2) { + init_val = __crc32h(init_val, *(const uint16_t *)pd); + pd += 2; + } + + if (data_len & 0x1) + init_val = __crc32b(init_val, *(const uint8_t *)pd); + + return init_val; +} + +static inline uint32_t _odp_hash_crc32c(const void *data, uint32_t data_len, + uint32_t init_val) +{ + uint32_t i; + uintptr_t pd = (uintptr_t)data; + + for (i = 0; i < data_len / 8; i++) { + init_val = __crc32cd(init_val, *(const uint64_t *)pd); + pd += 8; + } + + if (data_len & 0x4) { + init_val = __crc32cw(init_val, *(const uint32_t *)pd); + pd += 4; + } + + if (data_len & 0x2) { + init_val = __crc32ch(init_val, *(const uint16_t *)pd); + pd += 2; + } + + if (data_len & 0x1) + init_val = __crc32cb(init_val, *(const uint8_t *)pd); + + return init_val; +} + +#else /* __ARM_FEATURE_CRC32 */ + +/* + * Fall back to software implementation + */ + +static inline uint32_t _odp_hash_crc32(const void *data, uint32_t data_len, + uint32_t init_val) +{ + return _odp_hash_crc32_generic(data, data_len, init_val); +} + +static inline uint32_t _odp_hash_crc32c(const void *data, uint32_t data_len, + uint32_t init_val) +{ + return _odp_hash_crc32c_generic(data, data_len, init_val); +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3 From 2010f8f62a58d032c3f1ec3987200e5101284eb1 Mon Sep 17 00:00:00 2001 From: Harman Kalra Date: Tue, 26 Jan 2021 15:23:29 +0530 Subject: validation: pktio: fix segment length pool param During pool creation segment length (param.pkt.seg_len) gets initialised with max segment length possible (which could go up to max packet length supported in case of single segmented buffer), while packet length (param.pkt.len) value gets initialised with PKT_BUF_SIZE. With this initialisation seg length becomes much greater than packet length i.e. (param.pkt.seg_len > param.pkt.len). With given pool params, expectation is to support param.pkt.num packets of param.pkt.len with first buffer segment size as param.pkt.seg_len, which is not feasible. Signed-off-by: Harman Kalra Reviewed-by: Matias Elo --- test/validation/api/pktio/pktio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/validation/api/pktio/pktio.c b/test/validation/api/pktio/pktio.c index 185545fe9..87d5b6ad4 100644 --- a/test/validation/api/pktio/pktio.c +++ b/test/validation/api/pktio/pktio.c @@ -140,7 +140,8 @@ static void set_pool_len(odp_pool_param_t *params, odp_pool_capability_t *capa) len = (capa->pkt.max_len && capa->pkt.max_len < PKT_BUF_SIZE) ? capa->pkt.max_len : PKT_BUF_SIZE; - seg_len = capa->pkt.max_seg_len ? capa->pkt.max_seg_len : PKT_BUF_SIZE; + seg_len = (capa->pkt.max_seg_len && capa->pkt.max_seg_len < PKT_BUF_SIZE) ? + capa->pkt.max_seg_len : PKT_BUF_SIZE; switch (pool_segmentation) { case PKT_POOL_SEGMENTED: -- cgit v1.2.3 From afd39af41057246799275caa90d92f3a564670e8 Mon Sep 17 00:00:00 2001 From: Aakash Sasidharan Date: Wed, 6 Jan 2021 02:44:46 +0000 Subject: example: ipsec: use comma as separator in args As part of -i option, interface name could be in PCI Domain Bus Device Function (DBDF) format to represent the device. Application will throw error during argument parsing as DBDF format itself contains colon(:). So updating parsing logic to use comma(,) as a separator instead of colon(:). Also updating MAC address representation to use colons as colon is no longer reserved for field separation. Signed-off-by: Aakash Sasidharan Reviewed-by: Janne Peltonen --- example/ipsec_api/README | 12 ++++++------ example/ipsec_api/odp_ipsec.c | 20 ++++++++++---------- example/ipsec_api/odp_ipsec_api_run_ah_in.sh | 8 ++++---- example/ipsec_api/odp_ipsec_api_run_ah_out.sh | 8 ++++---- example/ipsec_api/odp_ipsec_api_run_ah_tun_in.sh | 10 +++++----- example/ipsec_api/odp_ipsec_api_run_ah_tun_out.sh | 10 +++++----- example/ipsec_api/odp_ipsec_api_run_esp_in.sh | 10 +++++----- example/ipsec_api/odp_ipsec_api_run_esp_out.sh | 10 +++++----- example/ipsec_api/odp_ipsec_api_run_esp_tun_in.sh | 12 ++++++------ example/ipsec_api/odp_ipsec_api_run_esp_tun_out.sh | 10 +++++----- example/ipsec_api/odp_ipsec_api_run_live.sh | 16 ++++++++-------- example/ipsec_api/odp_ipsec_api_run_router.sh | 4 ++-- example/ipsec_api/odp_ipsec_api_run_simple.sh | 4 ++-- example/ipsec_crypto/README | 16 ++++++++-------- example/ipsec_crypto/odp_ipsec.c | 20 ++++++++++---------- example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh | 8 ++++---- example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh | 8 ++++---- example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh | 12 ++++++------ .../ipsec_crypto/odp_ipsec_crypto_run_both_out.sh | 12 ++++++------ example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh | 10 +++++----- example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh | 10 +++++----- example/ipsec_crypto/odp_ipsec_crypto_run_live.sh | 20 ++++++++++---------- example/ipsec_crypto/odp_ipsec_crypto_run_router.sh | 4 ++-- example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh | 4 ++-- example/ipsec_crypto/odp_ipsec_fwd_db.c | 4 ++-- example/ipsec_crypto/odp_ipsec_fwd_db.h | 2 +- example/ipsec_crypto/odp_ipsec_misc.h | 6 +++--- example/ipsec_crypto/odp_ipsec_sa_db.c | 8 ++++---- example/ipsec_crypto/odp_ipsec_sa_db.h | 4 ++-- example/ipsec_crypto/odp_ipsec_sp_db.c | 4 ++-- example/ipsec_crypto/odp_ipsec_sp_db.h | 2 +- example/ipsec_crypto/odp_ipsec_stream.c | 4 ++-- example/ipsec_crypto/odp_ipsec_stream.h | 2 +- 33 files changed, 147 insertions(+), 147 deletions(-) diff --git a/example/ipsec_api/README b/example/ipsec_api/README index b391a6bfd..f7ea93e59 100644 --- a/example/ipsec_api/README +++ b/example/ipsec_api/README @@ -81,12 +81,12 @@ ONBOOT=yes The application is launched on VM1 with the following command: $ sudo ./odp_ipsec_api -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:esp \ --e 192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --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 \ +-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,esp \ +-e 192.168.111.2,192.168.222.2,3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-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 \ -c 2 -m 0 4.3 VM2 configuration diff --git a/example/ipsec_api/odp_ipsec.c b/example/ipsec_api/odp_ipsec.c index e6a3716be..98e31d6ce 100644 --- a/example/ipsec_api/odp_ipsec.c +++ b/example/ipsec_api/odp_ipsec.c @@ -1325,26 +1325,26 @@ static void usage(char *progname) " 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)\n" - " -e, --esp SrcIP:DstIP:(3des|null):SPI:Key192\n" - " -a, --ah SrcIP:DstIP:(sha256|md5|null):SPI:Key(256|128)\n" + " -r, --route SubNet,Intf,NextHopMAC\n" + " -p, --policy SrcSubNet,DstSubNet,(in|out),(ah|esp)\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" + " Where: NextHopMAC is raw hex/colon 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" + " -r 192.168.222.0/24,p8p1,08:00:27:F5:8B:DB\n" + " -p 192.168.111.0/24,192.168.222.0/24,out,esp\n" + " -e 192.168.111.2,192.168.222.2,3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n" + " -a 192.168.111.2,192.168.222.2,md5,201,a731649644c5dee92cbd9c2e7e188ee6\n" "\n" "Optional OPTIONS\n" " -c, --count CPU count, 0=all available, default=1\n" - " -s, --stream SrcIP:DstIP:InIntf:OutIntf:Count:Length\n" + " -s, --stream SrcIP,DstIP,InIntf,OutIntf,Count,Length\n" " -h, --help Display help and exit.\n" " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n" " to enable use of poll queues instead of scheduled (default)\n" diff --git a/example/ipsec_api/odp_ipsec_api_run_ah_in.sh b/example/ipsec_api/odp_ipsec_api_run_ah_in.sh index 4f92849b2..22a56f380 100755 --- a/example/ipsec_api/odp_ipsec_api_run_ah_in.sh +++ b/example/ipsec_api/odp_ipsec_api_run_ah_in.sh @@ -5,8 +5,8 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_api -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 \ +-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_api_run_ah_out.sh b/example/ipsec_api/odp_ipsec_api_run_ah_out.sh index 67dff4c32..8194485a4 100755 --- a/example/ipsec_api/odp_ipsec_api_run_ah_out.sh +++ b/example/ipsec_api/odp_ipsec_api_run_ah_out.sh @@ -5,8 +5,8 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_api -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 \ +-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_api_run_ah_tun_in.sh b/example/ipsec_api/odp_ipsec_api_run_ah_tun_in.sh index fa33f260c..89331bbea 100755 --- a/example/ipsec_api/odp_ipsec_api_run_ah_tun_in.sh +++ b/example/ipsec_api/odp_ipsec_api_run_ah_tun_in.sh @@ -5,9 +5,9 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_api -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 \ +-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_api_run_ah_tun_out.sh b/example/ipsec_api/odp_ipsec_api_run_ah_tun_out.sh index acc25e8b2..bd15f5956 100755 --- a/example/ipsec_api/odp_ipsec_api_run_ah_tun_out.sh +++ b/example/ipsec_api/odp_ipsec_api_run_ah_tun_out.sh @@ -5,9 +5,9 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_api -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 \ +-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_api_run_esp_in.sh b/example/ipsec_api/odp_ipsec_api_run_esp_in.sh index d71c6f567..61873bf76 100755 --- a/example/ipsec_api/odp_ipsec_api_run_esp_in.sh +++ b/example/ipsec_api/odp_ipsec_api_run_esp_in.sh @@ -5,9 +5,9 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_api -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 \ +-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_api_run_esp_out.sh b/example/ipsec_api/odp_ipsec_api_run_esp_out.sh index e846dfbec..834daa4cc 100755 --- a/example/ipsec_api/odp_ipsec_api_run_esp_out.sh +++ b/example/ipsec_api/odp_ipsec_api_run_esp_out.sh @@ -10,9 +10,9 @@ IPSEC_EXAMPLE_PATH=. fi ${IPSEC_EXAMPLE_PATH}/odp_ipsec_api -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 \ +-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_api_run_esp_tun_in.sh b/example/ipsec_api/odp_ipsec_api_run_esp_tun_in.sh index def6f6abd..42be4559f 100755 --- a/example/ipsec_api/odp_ipsec_api_run_esp_tun_in.sh +++ b/example/ipsec_api/odp_ipsec_api_run_esp_tun_in.sh @@ -5,10 +5,10 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_api -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 \ +-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_api_run_esp_tun_out.sh b/example/ipsec_api/odp_ipsec_api_run_esp_tun_out.sh index d5dc6e0e6..7b0c42bcb 100755 --- a/example/ipsec_api/odp_ipsec_api_run_esp_tun_out.sh +++ b/example/ipsec_api/odp_ipsec_api_run_esp_tun_out.sh @@ -5,9 +5,9 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_api -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 \ +-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_api_run_live.sh b/example/ipsec_api/odp_ipsec_api_run_live.sh index 3af05d110..318e640fe 100755 --- a/example/ipsec_api/odp_ipsec_api_run_live.sh +++ b/example/ipsec_api/odp_ipsec_api_run_live.sh @@ -4,12 +4,12 @@ # - 2 interfaces interfaces # - Specify API mode on command line sudo ./odp_ipsec_api -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:esp \ --e 192.168.111.2:192.168.222.2:\ -3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --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 \ +-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,esp \ +-e 192.168.111.2,192.168.222.2,\ +3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-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 \ -c 2 "$@" diff --git a/example/ipsec_api/odp_ipsec_api_run_router.sh b/example/ipsec_api/odp_ipsec_api_run_router.sh index 34573d47f..2cdbd2272 100755 --- a/example/ipsec_api/odp_ipsec_api_run_router.sh +++ b/example/ipsec_api/odp_ipsec_api_run_router.sh @@ -4,6 +4,6 @@ # - 2 interfaces interfaces # - Specify API mode on command line sudo ./odp_ipsec_api -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 \ +-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_api_run_simple.sh b/example/ipsec_api/odp_ipsec_api_run_simple.sh index 8b9b9d7b9..56c022291 100755 --- a/example/ipsec_api/odp_ipsec_api_run_simple.sh +++ b/example/ipsec_api/odp_ipsec_api_run_simple.sh @@ -10,6 +10,6 @@ IPSEC_EXAMPLE_PATH=. fi ${IPSEC_EXAMPLE_PATH}/odp_ipsec_api -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 \ +-r 192.168.222.2/32,loop2,08:00:27:F5:8B:DB \ +-s 192.168.111.2,192.168.222.2,loop1,loop2,10,100 \ -c 2 "$@" diff --git a/example/ipsec_crypto/README b/example/ipsec_crypto/README index 9a3fdc4b9..8e66372b5 100644 --- a/example/ipsec_crypto/README +++ b/example/ipsec_crypto/README @@ -78,14 +78,14 @@ VM1 has the following interface configurations: The application is launched on VM1 with the following command: sudo ./odp_ipsec_crypto -i p7p1,p8p1 \ - -r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ - -r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ - -p 192.168.111.0/24:192.168.222.0/24:out:both \ - -e 192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ - -a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ - -p 192.168.222.0/24:192.168.111.0/24:in:both \ - -e 192.168.222.2:192.168.111.2:3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ - -a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ + -r 192.168.111.2/32,p7p1,08:00:27:76:B5:E0 \ + -r 192.168.222.2/32,p8p1,08:00:27:F5:8B:DB \ + -p 192.168.111.0/24,192.168.222.0/24,out,both \ + -e 192.168.111.2,192.168.222.2,3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ + -a 192.168.111.2,192.168.222.2,md5,200,a731649644c5dee92cbd9c2e7e188ee6 \ + -p 192.168.222.0/24,192.168.111.0/24,in,both \ + -e 192.168.222.2,192.168.111.2,3des,301,c966199f24d095f3990a320d749056401e82b26570320292 \ + -a 192.168.222.2,192.168.111.2,md5,300,27f6d123d7077b361662fc6e451f65d8 \ -c 2 -m 0 4.3 VM2 configuration diff --git a/example/ipsec_crypto/odp_ipsec.c b/example/ipsec_crypto/odp_ipsec.c index c4f34cbfa..bc70f643c 100644 --- a/example/ipsec_crypto/odp_ipsec.c +++ b/example/ipsec_crypto/odp_ipsec.c @@ -1627,26 +1627,26 @@ static void usage(char *progname) " Default: 0: SYNC api mode\n" "\n" "Routing / IPSec OPTIONS:\n" - " -r, --route SubNet:Intf:NextHopMAC\n" - " -p, --policy SrcSubNet:DstSubNet:(in|out):(ah|esp|both)\n" - " -e, --esp SrcIP:DstIP:(3des|null):SPI:Key192\n" - " -a, --ah SrcIP:DstIP:(sha256|md5|null):SPI:Key(256|128)\n" + " -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" + " Where: NextHopMAC is raw hex/colon 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" + " -r 192.168.222.0/24,p8p1,08:00:27:F5:8B:DB\n" + " -p 192.168.111.0/24,192.168.222.0/24,out,esp\n" + " -e 192.168.111.2,192.168.222.2,3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n" + " -a 192.168.111.2,192.168.222.2,md5,201,a731649644c5dee92cbd9c2e7e188ee6\n" "\n" "Optional OPTIONS\n" " -c, --count CPU count, 0=all available, default=1\n" - " -s, --stream SrcIP:DstIP:InIntf:OutIntf:Count:Length\n" + " -s, --stream SrcIP,DstIP,InIntf,OutIntf,Count,Length\n" " -h, --help Display help and exit.\n" " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n" " to enable use of poll queues instead of scheduled (default)\n" diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh index 18045c7e9..b64fd7d2d 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_in.sh @@ -5,8 +5,8 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_crypto -i loop1,loop2 \ --r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ --p 192.168.222.0/24:192.168.111.0/24:in:ah \ --a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ --s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-r 192.168.111.2/32,loop1,08:00:27:76:B5:E0 \ +-p 192.168.222.0/24,192.168.111.0/24,in,ah \ +-a 192.168.222.2,192.168.111.2,md5,300,27f6d123d7077b361662fc6e451f65d8 \ +-s 192.168.222.2,192.168.111.2,loop2,loop1,10,100 \ -c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh index 8ddfd203d..0ff42289c 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_ah_out.sh @@ -5,8 +5,8 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_crypto -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:ah \ --a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-r 192.168.222.2/32,loop2,08:00:27:F5:8B:DB \ +-p 192.168.111.0/24,192.168.222.0/24,out,ah \ +-a 192.168.111.2,192.168.222.2,md5,200,a731649644c5dee92cbd9c2e7e188ee6 \ +-s 192.168.111.2,192.168.222.2,loop1,loop2,10,100 \ -c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh index 4ad08a784..a986b713e 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_both_in.sh @@ -5,10 +5,10 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_crypto -i loop1,loop2 \ --r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ --p 192.168.222.0/24:192.168.111.0/24:in:both \ --a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ --e 192.168.222.2:192.168.111.2:\ -3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ --s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-r 192.168.111.2/32,loop1,08:00:27:76:B5:E0 \ +-p 192.168.222.0/24,192.168.111.0/24,in,both \ +-a 192.168.222.2,192.168.111.2,md5,300,27f6d123d7077b361662fc6e451f65d8 \ +-e 192.168.222.2,192.168.111.2,\ +3des,301,c966199f24d095f3990a320d749056401e82b26570320292 \ +-s 192.168.222.2,192.168.111.2,loop2,loop1,10,100 \ -c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh index a9e3ac8af..ebbcde071 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_both_out.sh @@ -5,10 +5,10 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_crypto -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:both \ --e 192.168.111.2:192.168.222.2:\ -3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-r 192.168.222.2/32,loop2,08:00:27:F5:8B:DB \ +-p 192.168.111.0/24,192.168.222.0/24,out,both \ +-e 192.168.111.2,192.168.222.2,\ +3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-a 192.168.111.2,192.168.222.2,md5,200,a731649644c5dee92cbd9c2e7e188ee6 \ +-s 192.168.111.2,192.168.222.2,loop1,loop2,10,100 \ -c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh index 62f73cf7d..cdf84c517 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_in.sh @@ -5,9 +5,9 @@ # - 10 packets # - Specify API mode on command line ./odp_ipsec_crypto -i loop1,loop2 \ --r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \ --p 192.168.222.0/24:192.168.111.0/24:in:esp \ --e 192.168.222.2:192.168.111.2:\ -3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ --s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \ +-r 192.168.111.2/32,loop1,08:00:27:76:B5:E0 \ +-p 192.168.222.0/24,192.168.111.0/24,in,esp \ +-e 192.168.222.2,192.168.111.2,\ +3des,301,c966199f24d095f3990a320d749056401e82b26570320292 \ +-s 192.168.222.2,192.168.111.2,loop2,loop1,10,100 \ -c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh index cd9db1e2a..ae257be4f 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_esp_out.sh @@ -10,9 +10,9 @@ IPSEC_EXAMPLE_PATH=. fi ${IPSEC_EXAMPLE_PATH}/odp_ipsec_crypto -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:esp \ --e 192.168.111.2:192.168.222.2:\ -3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-r 192.168.222.2/32,loop2,08:00:27:F5:8B:DB \ +-p 192.168.111.0/24,192.168.222.0/24,out,esp \ +-e 192.168.111.2,192.168.222.2,\ +3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-s 192.168.111.2,192.168.222.2,loop1,loop2,10,100 \ -c 2 "$@" diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_live.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_live.sh index e893674bc..c212097e0 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_live.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_live.sh @@ -4,14 +4,14 @@ # - 2 interfaces interfaces # - Specify API mode on command line sudo ./odp_ipsec_crypto -i p7p1,p8p1 \ --r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ --r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ --p 192.168.111.0/24:192.168.222.0/24:out:both \ --e 192.168.111.2:192.168.222.2:\ -3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ --a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \ --p 192.168.222.0/24:192.168.111.0/24:in:both \ --e 192.168.222.2:192.168.111.2:\ -3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \ --a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \ +-r 192.168.111.2/32,p7p1,08:00:27:76:B5:E0 \ +-r 192.168.222.2/32,p8p1,08:00:27:F5:8B:DB \ +-p 192.168.111.0/24,192.168.222.0/24,out,both \ +-e 192.168.111.2,192.168.222.2,\ +3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \ +-a 192.168.111.2,192.168.222.2,md5,200,a731649644c5dee92cbd9c2e7e188ee6 \ +-p 192.168.222.0/24,192.168.111.0/24,in,both \ +-e 192.168.222.2,192.168.111.2,\ +3des,301,c966199f24d095f3990a320d749056401e82b26570320292 \ +-a 192.168.222.2,192.168.111.2,md5,300,27f6d123d7077b361662fc6e451f65d8 \ -c 2 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_router.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_router.sh index 920f28e0d..d08490946 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_router.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_router.sh @@ -4,6 +4,6 @@ # - 2 interfaces interfaces # - Specify API mode on command line sudo ./odp_ipsec_crypto -i p7p1,p8p1 \ --r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \ --r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \ +-r 192.168.111.2/32,p7p1,08:00:27:76:B5:E0 \ +-r 192.168.222.2/32,p8p1,08:00:27:F5:8B:DB \ -c 1 -m $1 diff --git a/example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh b/example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh index 3613fe5fd..5d3abcd51 100755 --- a/example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh +++ b/example/ipsec_crypto/odp_ipsec_crypto_run_simple.sh @@ -10,6 +10,6 @@ IPSEC_EXAMPLE_PATH=. fi ${IPSEC_EXAMPLE_PATH}/odp_ipsec_crypto -i loop1,loop2 \ --r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \ --s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \ +-r 192.168.222.2/32,loop2,08:00:27:F5:8B:DB \ +-s 192.168.111.2,192.168.222.2,loop1,loop2,10,100 \ -c 2 "$@" diff --git a/example/ipsec_crypto/odp_ipsec_fwd_db.c b/example/ipsec_crypto/odp_ipsec_fwd_db.c index ca0abf6c1..9bd399ca9 100644 --- a/example/ipsec_crypto/odp_ipsec_fwd_db.c +++ b/example/ipsec_crypto/odp_ipsec_fwd_db.c @@ -66,8 +66,8 @@ int create_fwd_db_entry(char *input, char **if_names, int if_count) str = local; save = NULL; - /* Parse tokens separated by ':' */ - while (NULL != (token = strtok_r(str, ":", &save))) { + /* 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 */ diff --git a/example/ipsec_crypto/odp_ipsec_fwd_db.h b/example/ipsec_crypto/odp_ipsec_fwd_db.h index 278259729..46fda2b87 100644 --- a/example/ipsec_crypto/odp_ipsec_fwd_db.h +++ b/example/ipsec_crypto/odp_ipsec_fwd_db.h @@ -47,7 +47,7 @@ void init_fwd_db(void); /** * Create a forwarding database entry * - * String is of the format "SubNet:Intf:NextHopMAC" + * String is of the format "SubNet,Intf,NextHopMAC" * * @param input Pointer to string describing route * diff --git a/example/ipsec_crypto/odp_ipsec_misc.h b/example/ipsec_crypto/odp_ipsec_misc.h index 71d8f63c4..0ff3fc0c7 100644 --- a/example/ipsec_crypto/odp_ipsec_misc.h +++ b/example/ipsec_crypto/odp_ipsec_misc.h @@ -233,7 +233,7 @@ char *ipv4_subnet_str(char *b, ip_addr_range_t *range) static inline char *mac_addr_str(char *b, uint8_t *mac) { - sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X", + sprintf(b, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return b; } @@ -241,7 +241,7 @@ char *mac_addr_str(char *b, uint8_t *mac) /** * 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 + * 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 @@ -255,7 +255,7 @@ int parse_mac_string(char *macaddress, uint8_t *mac) int converted; converted = sscanf(macaddress, - "%x.%x.%x.%x.%x.%x", + "%x:%x:%x:%x:%x:%x", &macwords[0], &macwords[1], &macwords[2], &macwords[3], &macwords[4], &macwords[5]); if (6 != converted) diff --git a/example/ipsec_crypto/odp_ipsec_sa_db.c b/example/ipsec_crypto/odp_ipsec_sa_db.c index 9a7c593b3..ff9d7e3c7 100644 --- a/example/ipsec_crypto/odp_ipsec_sa_db.c +++ b/example/ipsec_crypto/odp_ipsec_sa_db.c @@ -95,8 +95,8 @@ int create_sa_db_entry(char *input, odp_bool_t cipher) str = local; save = NULL; - /* Parse tokens separated by ':' */ - while (NULL != (token = strtok_r(str, ":", &save))) { + /* 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 */ @@ -191,8 +191,8 @@ int create_tun_db_entry(char *input) str = local; save = NULL; - /* Parse tokens separated by ':' */ - while (NULL != (token = strtok_r(str, ":", &save))) { + /* 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 */ diff --git a/example/ipsec_crypto/odp_ipsec_sa_db.h b/example/ipsec_crypto/odp_ipsec_sa_db.h index 729d98d56..97f9249db 100644 --- a/example/ipsec_crypto/odp_ipsec_sa_db.h +++ b/example/ipsec_crypto/odp_ipsec_sa_db.h @@ -48,7 +48,7 @@ void init_sa_db(void); /** * Create an SA DB entry * - * String is of the format "SrcIP:DstIP:Alg:SPI:Key" + * 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 @@ -100,7 +100,7 @@ void init_tun_db(void); /** * Create an tunnel DB entry * - * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp" + * String is of the format "SrcIP,DstIP,TunSrcIp,TunDstIp" * * @param input Pointer to string describing tun * diff --git a/example/ipsec_crypto/odp_ipsec_sp_db.c b/example/ipsec_crypto/odp_ipsec_sp_db.c index 1e5820b47..3ead3b0a3 100644 --- a/example/ipsec_crypto/odp_ipsec_sp_db.c +++ b/example/ipsec_crypto/odp_ipsec_sp_db.c @@ -66,8 +66,8 @@ int create_sp_db_entry(char *input, odp_bool_t both_supported) str = local; save = NULL; - /* Parse tokens separated by ':' */ - while (NULL != (token = strtok_r(str, ":", &save))) { + /* 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 */ diff --git a/example/ipsec_crypto/odp_ipsec_sp_db.h b/example/ipsec_crypto/odp_ipsec_sp_db.h index 878f3a7c4..b71ea9377 100644 --- a/example/ipsec_crypto/odp_ipsec_sp_db.h +++ b/example/ipsec_crypto/odp_ipsec_sp_db.h @@ -43,7 +43,7 @@ void init_sp_db(void); /** * Create an SP DB entry * - * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|[both])" + * String is of the format "SrcSubNet,DstSubNet,(in|out),(ah|esp|[both])" * * @param input Pointer to a string describing SP * @param both_supported Enabling both AH and ESP is supported diff --git a/example/ipsec_crypto/odp_ipsec_stream.c b/example/ipsec_crypto/odp_ipsec_stream.c index d689c6198..db4130fe7 100644 --- a/example/ipsec_crypto/odp_ipsec_stream.c +++ b/example/ipsec_crypto/odp_ipsec_stream.c @@ -83,8 +83,8 @@ int create_stream_db_entry(char *input) str = local; save = NULL; - /* Parse tokens separated by ':' */ - while (NULL != (token = strtok_r(str, ":", &save))) { + /* 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 */ diff --git a/example/ipsec_crypto/odp_ipsec_stream.h b/example/ipsec_crypto/odp_ipsec_stream.h index b32f1d7cb..685b4ee86 100644 --- a/example/ipsec_crypto/odp_ipsec_stream.h +++ b/example/ipsec_crypto/odp_ipsec_stream.h @@ -58,7 +58,7 @@ void init_stream_db(void); /** * Create an stream DB entry * - * String is of the format "SrcIP:DstIP:InInt:OutIntf:Count:Length" + * String is of the format "SrcIP,DstIP,InInt,OutIntf,Count,Length" * * @param input Pointer to string describing stream * -- cgit v1.2.3 From 2c7116122a6613e928869e773acbd4337dc585a7 Mon Sep 17 00:00:00 2001 From: Malvika Gupta Date: Wed, 3 Feb 2021 14:51:36 -0600 Subject: linux-gen: packet: add segment index when printing per segment data To make the original format of printing per segment data clearer, the segment index has been added and printed as well. Signed-off-by: Malvika Gupta Reviewed-by: Govindarajan Mohandoss Reviewed-by: Matias Elo --- platform/linux-generic/odp_packet.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c index dac2100ee..dd783acd9 100644 --- a/platform/linux-generic/odp_packet.c +++ b/platform/linux-generic/odp_packet.c @@ -1605,15 +1605,16 @@ void odp_packet_print(odp_packet_t pkt) seg = odp_packet_first_seg(pkt); - while (seg != ODP_PACKET_SEG_INVALID) { + for (int seg_idx = 0; seg != ODP_PACKET_SEG_INVALID; seg_idx++) { odp_packet_hdr_t *seg_hdr = packet_seg_to_hdr(seg); odp_buffer_hdr_t *buf_hdr = &seg_hdr->buf_hdr; char seg_str[max_len]; int str_len; str_len = snprintf(&seg_str[0], max_len, - " seg_len %-4" PRIu32 " seg_data %p " - "ref_cnt %u\n", + " [%d] seg_len %-4" PRIu32 " seg_data %p " + " ref_cnt %u\n", + seg_idx, odp_packet_seg_data_len(pkt, seg), odp_packet_seg_data(pkt, seg), buffer_ref(buf_hdr)); -- cgit v1.2.3 From 11ed8e34d095119a7725975a892c33a6c4e0891a Mon Sep 17 00:00:00 2001 From: Janne Peltonen Date: Fri, 29 Jan 2021 15:35:40 +0200 Subject: linux-gen: thread: read maximum number of threads from config file Add system:thread_count_max config parameter that can be used to reduce the maximum number of threads below the build time configured maximum. This can be used to reduce thread related resource consumption such as thread-local memory. Most code still uses the build time limit, ODP_THREAD_COUNT_MAX, so this change merely enables possible later optimizations in those cases. ODP-DPDK will already benefit from this change as the number of queue pairs for a crypto device can be lowered to match the actual number of threads without ODP-DPDK having worry about possible sharing of the queue pairs between threads. Signed-off-by: Janne Peltonen Reviewed-by: Matias Elo --- config/odp-linux-generic.conf | 8 +++++++- platform/linux-generic/m4/odp_libconfig.m4 | 2 +- platform/linux-generic/odp_thread.c | 27 +++++++++++++++++++++++---- platform/linux-generic/test/inline-timer.conf | 2 +- platform/linux-generic/test/packet_align.conf | 2 +- platform/linux-generic/test/process-mode.conf | 2 +- 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/config/odp-linux-generic.conf b/config/odp-linux-generic.conf index a03c8568f..bb25c39b2 100644 --- a/config/odp-linux-generic.conf +++ b/config/odp-linux-generic.conf @@ -16,7 +16,7 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.14" +config_file_version = "0.1.15" # System options system: { @@ -29,6 +29,12 @@ system: { # odp_cpu_hz_max_id() calls on platforms where max frequency isn't # available using standard Linux methods. cpu_mhz_max = 1400 + + # Maximum number of ODP threads that can be created. + # odp_thread_count_max() returns this value or the build time + # maximum ODP_THREAD_COUNT_MAX, whichever is lower. This setting + # can be used to reduce thread related resource usage. + thread_count_max = 256 } # Shared memory options diff --git a/platform/linux-generic/m4/odp_libconfig.m4 b/platform/linux-generic/m4/odp_libconfig.m4 index 325c62ad0..7a0b45497 100644 --- a/platform/linux-generic/m4/odp_libconfig.m4 +++ b/platform/linux-generic/m4/odp_libconfig.m4 @@ -3,7 +3,7 @@ ########################################################################## m4_define([_odp_config_version_generation], [0]) m4_define([_odp_config_version_major], [1]) -m4_define([_odp_config_version_minor], [14]) +m4_define([_odp_config_version_minor], [15]) m4_define([_odp_config_version], [_odp_config_version_generation._odp_config_version_major._odp_config_version_minor]) diff --git a/platform/linux-generic/odp_thread.c b/platform/linux-generic/odp_thread.c index bec7362bf..170bf82b7 100644 --- a/platform/linux-generic/odp_thread.c +++ b/platform/linux-generic/odp_thread.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -18,6 +19,7 @@ #include #include #include +#include #include #include @@ -35,6 +37,7 @@ typedef struct { uint32_t num; uint32_t num_worker; uint32_t num_control; + uint32_t num_max; odp_spinlock_t lock; } thread_globals_t; @@ -51,6 +54,19 @@ __thread _odp_thread_state_t *_odp_this_thread; int _odp_thread_init_global(void) { odp_shm_t shm; + int num_max = 0; + const char *str = "system.thread_count_max"; + + if (!_odp_libconfig_lookup_int(str, &num_max)) { + ODP_ERR("Config option '%s' not found.\n", str); + return -1; + } + if (num_max <= 0) { + ODP_ERR("Config option '%s' not valid.\n", str); + return -1; + } + if (num_max > ODP_THREAD_COUNT_MAX) + num_max = ODP_THREAD_COUNT_MAX; shm = odp_shm_reserve("_odp_thread_globals", sizeof(thread_globals_t), @@ -63,6 +79,9 @@ int _odp_thread_init_global(void) memset(thread_globals, 0, sizeof(thread_globals_t)); odp_spinlock_init(&thread_globals->lock); + thread_globals->num_max = num_max; + ODP_PRINT("System config:\n"); + ODP_PRINT(" system.thread_count_max: %d\n\n", num_max); return 0; } @@ -83,10 +102,10 @@ static int alloc_id(odp_thread_type_t type) int thr; odp_thrmask_t *all = &thread_globals->all; - if (thread_globals->num >= ODP_THREAD_COUNT_MAX) + if (thread_globals->num >= thread_globals->num_max) return -1; - for (thr = 0; thr < ODP_THREAD_COUNT_MAX; thr++) { + for (thr = 0; thr < (int)thread_globals->num_max; thr++) { if (odp_thrmask_isset(all, thr) == 0) { odp_thrmask_set(all, thr); @@ -110,7 +129,7 @@ static int free_id(int thr) { odp_thrmask_t *all = &thread_globals->all; - if (thr < 0 || thr >= ODP_THREAD_COUNT_MAX) + if (thr < 0 || thr >= (int)thread_globals->num_max) return -1; if (odp_thrmask_isset(all, thr) == 0) @@ -231,7 +250,7 @@ int odp_thread_count(void) int odp_thread_count_max(void) { - return ODP_THREAD_COUNT_MAX; + return thread_globals->num_max; } int odp_thrmask_worker(odp_thrmask_t *mask) diff --git a/platform/linux-generic/test/inline-timer.conf b/platform/linux-generic/test/inline-timer.conf index 096aab055..e4d4af307 100644 --- a/platform/linux-generic/test/inline-timer.conf +++ b/platform/linux-generic/test/inline-timer.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.14" +config_file_version = "0.1.15" timer: { # Enable inline timer implementation diff --git a/platform/linux-generic/test/packet_align.conf b/platform/linux-generic/test/packet_align.conf index 24ed46b56..9b37752ba 100644 --- a/platform/linux-generic/test/packet_align.conf +++ b/platform/linux-generic/test/packet_align.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.14" +config_file_version = "0.1.15" pool: { pkt: { diff --git a/platform/linux-generic/test/process-mode.conf b/platform/linux-generic/test/process-mode.conf index 8e18feb2c..5354cae2f 100644 --- a/platform/linux-generic/test/process-mode.conf +++ b/platform/linux-generic/test/process-mode.conf @@ -1,6 +1,6 @@ # Mandatory fields odp_implementation = "linux-generic" -config_file_version = "0.1.14" +config_file_version = "0.1.15" # Shared memory options shm: { -- cgit v1.2.3 From a2ae9164243ea6eb994e8e58c401e4d3e24d6b4c Mon Sep 17 00:00:00 2001 From: Aakash Sasidharan Date: Fri, 5 Feb 2021 06:41:33 +0000 Subject: example: remove ipsec_offload application Remove ipsec_offload application as it is mostly duplicate of the ipsec_api application. Signed-off-by: Aakash Sasidharan Reviewed-by: Petri Savolainen --- doc/application-api-guide/examples.dox | 5 - example/Makefile.am | 1 - example/ipsec_offload/.gitignore | 1 - example/ipsec_offload/Makefile.am | 18 - example/ipsec_offload/odp_ipsec_offload.c | 877 ----------------------- example/ipsec_offload/odp_ipsec_offload_cache.c | 145 ---- example/ipsec_offload/odp_ipsec_offload_cache.h | 78 -- example/ipsec_offload/odp_ipsec_offload_fwd_db.c | 226 ------ example/ipsec_offload/odp_ipsec_offload_fwd_db.h | 198 ----- example/ipsec_offload/odp_ipsec_offload_misc.h | 366 ---------- example/ipsec_offload/odp_ipsec_offload_sa_db.c | 365 ---------- example/ipsec_offload/odp_ipsec_offload_sa_db.h | 126 ---- example/ipsec_offload/odp_ipsec_offload_sp_db.c | 167 ----- example/ipsec_offload/odp_ipsec_offload_sp_db.h | 72 -- example/ipsec_offload/run_left.sh | 14 - example/ipsec_offload/run_right.sh | 14 - example/m4/configure.m4 | 1 - 17 files changed, 2674 deletions(-) delete mode 100644 example/ipsec_offload/.gitignore delete mode 100644 example/ipsec_offload/Makefile.am delete mode 100644 example/ipsec_offload/odp_ipsec_offload.c delete mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.c delete mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.h delete mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.c delete mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.h delete mode 100644 example/ipsec_offload/odp_ipsec_offload_misc.h delete mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.c delete mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.h delete mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.c delete mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.h delete mode 100755 example/ipsec_offload/run_left.sh delete mode 100755 example/ipsec_offload/run_right.sh diff --git a/doc/application-api-guide/examples.dox b/doc/application-api-guide/examples.dox index a45c3127e..98e66d72b 100644 --- a/doc/application-api-guide/examples.dox +++ b/doc/application-api-guide/examples.dox @@ -39,11 +39,6 @@ * IPsec example application using crypto API */ -/** - * @example ipsec_offload/odp_ipsec_offload.c - * IPsec offload example application - */ - /** * @example odp_l2fwd.c * L2 forwarding example application diff --git a/example/Makefile.am b/example/Makefile.am index 02ef55faf..fc4623d1f 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -4,7 +4,6 @@ SUBDIRS = classifier \ hello \ ipsec_api \ ipsec_crypto \ - ipsec_offload \ l2fwd_simple \ l3fwd \ packet \ diff --git a/example/ipsec_offload/.gitignore b/example/ipsec_offload/.gitignore deleted file mode 100644 index 2fc73aa3c..000000000 --- a/example/ipsec_offload/.gitignore +++ /dev/null @@ -1 +0,0 @@ -odp_ipsec_offload diff --git a/example/ipsec_offload/Makefile.am b/example/ipsec_offload/Makefile.am deleted file mode 100644 index 0afe4ffaf..000000000 --- a/example/ipsec_offload/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -include $(top_srcdir)/example/Makefile.inc - -bin_PROGRAMS = odp_ipsec_offload - -odp_ipsec_offload_SOURCES = odp_ipsec_offload.c \ - odp_ipsec_offload_misc.h \ - odp_ipsec_offload_sa_db.c \ - odp_ipsec_offload_sp_db.c \ - odp_ipsec_offload_fwd_db.c \ - odp_ipsec_offload_fwd_db.h \ - odp_ipsec_offload_cache.c \ - odp_ipsec_offload_cache.h \ - odp_ipsec_offload_sa_db.h \ - odp_ipsec_offload_sp_db.h - -dist_noinst_SCRIPTS = \ - run_left.sh \ - run_right.sh diff --git a/example/ipsec_offload/odp_ipsec_offload.c b/example/ipsec_offload/odp_ipsec_offload.c deleted file mode 100644 index a75b15c2a..000000000 --- a/example/ipsec_offload/odp_ipsec_offload.c +++ /dev/null @@ -1,877 +0,0 @@ -/* Copyright (c) 2017-2018, 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 -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* maximum number of worker threads */ -#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1) - -#define MAX_COMPL_QUEUES 32 - -/** - * Parsed command line application arguments - */ -typedef struct { - unsigned 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 global application data - */ -typedef struct { - /** Application (parsed) arguments */ - appl_args_t appl; - odp_pool_t pkt_pool; - /** Atomic queue IPSEC completion events */ - odp_queue_t completionq[MAX_COMPL_QUEUES]; - /** Synchronize threads before packet processing begins */ - odp_barrier_t sync_barrier; - int num_compl_queues; - int num_workers; -} global_data_t; - -/* helper funcs */ -static void parse_args(int argc, char *argv[], appl_args_t *appl_args); -static void print_info(char *progname, appl_args_t *appl_args); -static void usage(char *progname); - -/** Global pointer to args */ -static global_data_t *global; - -/** - * 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) - -/** - * 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 GET_THR_QUEUE_ID(x) ((odp_thread_id() - 1) % (x)) - -/** - * 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 %= global->num_workers; - if (global->num_compl_queues < global->num_workers) - global->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) { - odp_queue_t queue = global->completionq[queue_id - 1]; - - if (create_ipsec_cache_entry(cipher_sa, - auth_sa, - tun, - entry->input, - queue) - ) { - ODPH_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, global->pkt_pool, &pktio_param); - if (ODP_PKTIO_INVALID == pktio) - ODPH_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) - ODPH_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)) - ODPH_ABORT("Error: pktin config failed for %s\n", intf); - - if (odp_pktout_queue_config(pktio, NULL)) - ODPH_ABORT("Error: pktout config failed for %s\n", intf); - - if (odp_pktout_queue(pktio, &pktout, 1) != 1) - ODPH_ABORT("Error: failed to get pktout queue for %s\n", - intf); - - ret = odp_pktio_start(pktio); - if (ret) - ODPH_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) { - ODPH_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_out_param_t params; - uint32_t sip, dip; - uint64_t hash; - flow_entry_t *flow; - - 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 = route_flow_lookup_in_bucket(sip, dip, - &flow_table[hash & - (bucket_count - 1)]); - if (!flow) { - /*Check into Routing table*/ - fwd_entry = find_fwd_db_entry(dip); - if (!fwd_entry) { - ODPH_DBG("No flow match found. Packet is dropped.\n"); - odp_packet_free(pkt); - return PKT_DROP; - } - - /*Entry found. Updated in Flow table first.*/ - flow = calloc(1, sizeof(flow_entry_t)); - if (!flow) { - ODPH_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*/ - route_flow_insert_in_bucket(flow, &flow_table[hash & - (bucket_count - 1)]); - } - - 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)) { - ODPH_DBG("Unable to out enqueue\n"); - odp_packet_free(pkt); - return PKT_DROP; - } - return PKT_POSTED; -} - -/** - * 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_in_param_t params; - - if (!odp_packet_has_ipsec(pkt)) - return PKT_CONTINUE; - - /* Initialize parameters block */ - params.num_sa = 0; - params.sa = NULL; - - /* Issue ipsec request */ - if (odp_unlikely(odp_ipsec_in_enq(&pkt, 1, ¶ms) < 0)) { - ODPH_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 -int pktio_thread(void *arg ODP_UNUSED) -{ - int thr = odp_thread_id(); - odp_packet_t pkt; - odp_pktout_queue_t out_queue; - ipsec_out_entry_t *out_port; - odp_event_t ev = ODP_EVENT_INVALID; - - printf("Pktio thread [%02i] starts\n", thr); - odp_barrier_wait(&global->sync_barrier); - - /* Loop packets */ - for (;;) { - pkt_disposition_e rc; - odp_event_subtype_t subtype; - - ev = odp_schedule(NULL, ODP_SCHED_WAIT); - /* Use schedule to get event from any input queue */ - /* Determine new work versus IPsec result */ - if (ODP_EVENT_PACKET == odp_event_types(ev, &subtype)) { - pkt = odp_packet_from_event(ev); - - if (ODP_EVENT_PACKET_IPSEC == subtype) { - odp_ipsec_packet_result_t res; - - if (odp_unlikely(odp_ipsec_result(&res, - pkt) < 0)) { - ODPH_DBG("Error Event\n"); - odp_event_free((odp_event_t)ev); - continue; - } - - if (odp_unlikely(res.status.error.all)) { - odp_packet_free(pkt); - continue; - } - } else { - 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_packet_user_ptr(pkt); - out_queue = out_port->pktout; - - if (odp_unlikely(odp_pktout_send(out_queue, - &pkt, 1) < 0)) - odp_packet_free(pkt); - - } else { - ODPH_DBG("Invalid Event\n"); - odp_event_free(ev); - continue; - } - } - - /* unreachable */ - return 0; -} - -/** - * ODP ipsec proto example main function - */ -int -main(int argc, char *argv[]) -{ - odph_odpthread_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_odpthread_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)) - ODPH_ABORT("Error: ODP global init failed.\n"); - /* Initialize this thread */ - if (odp_init_local(instance, ODP_THREAD_CONTROL)) - ODPH_ABORT("Error: ODP local init failed.\n"); - /* Reserve memory for arguments from shared memory */ - shm = odp_shm_reserve("shm_args", sizeof(global_data_t), - ODP_CACHE_LINE_SIZE, 0); - - if (shm == ODP_SHM_INVALID) - ODPH_ABORT("Error: shared mem reserve failed.\n"); - - global = odp_shm_addr(shm); - - if (NULL == global) - ODPH_ABORT("Error: shared mem alloc failed.\n"); - memset(global, 0, sizeof(global_data_t)); - - /* Must init our databases before parsing args */ - ipsec_init_pre(); - init_fwd_db(); - - /* Parse and store the application arguments */ - parse_args(argc, argv, &global->appl); - - /*Initialize route table for user given parameter*/ - init_routing_table(); - - /* Print both system and application information */ - print_info(NO_PATH(argv[0]), &global->appl); - - if (odp_ipsec_capability(&capa)) - ODPH_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.inbound_mode = ODP_IPSEC_OP_MODE_ASYNC; - config.outbound_mode = ODP_IPSEC_OP_MODE_ASYNC; - } else { - ODPH_ABORT("Error: Sync mode not supported.\n"); - } - - if (odp_ipsec_config(&config)) - ODPH_ABORT("Error: IPSec not configured.\n"); - - global->num_workers = MAX_WORKERS; - if (global->appl.cpu_count && global->appl.cpu_count < MAX_WORKERS) - global->num_workers = global->appl.cpu_count; - - /* - * By default CPU #0 runs Linux kernel background tasks. - * Start mapping thread from CPU #1 - */ - global->num_workers = odp_cpumask_default_worker(&cpumask, - global->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 = global->appl.queue_type; - qparam.sched.group = ODP_SCHED_GROUP_ALL; - - for (i = 0; i < global->num_workers; i++) { - global->completionq[i] = odp_queue_create("completion", - &qparam); - if (ODP_QUEUE_INVALID == global->completionq[i]) - ODPH_ABORT("Error: completion queue creation failed\n"); - } - printf("num worker threads: %i\n", global->num_workers); - printf("first CPU: %i\n", odp_cpumask_first(&cpumask)); - printf("cpu mask: %s\n", cpumaskstr); - - /* Create a barrier to synchronize thread startup */ - odp_barrier_init(&global->sync_barrier, global->num_workers); - - /* Create packet buffer pool */ - odp_pool_param_init(¶ms); - params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.num = SHM_PKT_POOL_BUF_COUNT; - params.type = ODP_POOL_PACKET; - - global->pkt_pool = odp_pool_create("packet_pool", ¶ms); - - if (ODP_POOL_INVALID == global->pkt_pool) - ODPH_ABORT("Error: packet pool create failed.\n"); - - ipsec_init_post(); - - /* Configure scheduler */ - odp_schedule_config(NULL); - - /* Initialize interfaces (which resolves FWD DB entries */ - for (i = 0; i < global->appl.if_count; i++) - initialize_intf(global->appl.if_names[i], - global->appl.queue_type); - - printf(" Configured queues SYNC type: [%s]\n", - (global->appl.queue_type == 0) ? - "PARALLEL" : - (global->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_odpthreads_create(thread_tbl, &cpumask, - &thr_params); - odph_odpthreads_join(thread_tbl); - - /* Stop and close used pktio devices */ - for (i = 0; i < global->appl.if_count; i++) { - odp_pktio_t pktio = odp_pktio_lookup(global->appl.if_names[i]); - - if (pktio == ODP_PKTIO_INVALID) - continue; - - if (odp_pktio_stop(pktio) || odp_pktio_close(pktio)) { - ODPH_ERR("Error: failed to close pktio %s\n", - global->appl.if_names[i]); - exit(EXIT_FAILURE); - } - } - - free(global->appl.if_names); - free(global->appl.if_str); - - if (odp_shm_free(shm)) { - ODPH_ERR("Error: shm free global data\n"); - exit(EXIT_FAILURE); - } - - printf("Exit\n\n"); - return 0; -} - -/** - * Parse and store the command line arguments - * - * @param argc argument count - * @param argv[] argument vector - * @param appl_args Store application arguments here - */ -static void parse_args(int argc, char *argv[], appl_args_t *appl_args) -{ - int opt; - int long_index; - char *token; - size_t len; - int rc = 0; - int i; - - static 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->cpu_count = 1; /* use one worker by default */ - 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; - } - ODPH_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) - ODPH_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 routes count.\n" - " -c, --count CPU count, 0=all available, default=1\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 deleted file mode 100644 index e4ac3c6f3..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_cache.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2017 NXP. All rights reserved. - */ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include - -#include -#include - -#include - -/** Global pointer to ipsec_cache db */ -ipsec_cache_t *ipsec_cache; - -#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); - - if (shm == ODP_SHM_INVALID) - ODPH_ABORT("Error: shared mem reserve failed.\n"); - - ipsec_cache = odp_shm_addr(shm); - - if (ipsec_cache == NULL) - ODPH_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.inbound.lookup_mode = ODP_IPSEC_LOOKUP_SPI; - } else { - sa_params.dir = ODP_IPSEC_DIR_OUTBOUND; - - src_ip = odp_cpu_to_be_32(tun->tun_src_ip); - dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip); - sa_params.outbound.tunnel.type = ODP_IPSEC_TUNNEL_IPV4; - sa_params.outbound.tunnel.ipv4.src_addr = &src_ip; - sa_params.outbound.tunnel.ipv4.dst_addr = &dst_ip; - sa_params.outbound.tunnel.ipv4.ttl = IPDEFTTL; - sa_params.outbound.tunnel.ipv4.dscp = 0; - sa_params.outbound.tunnel.ipv4.df = 1; - } - - 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; - } - - 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 deleted file mode 100644 index c922b1803..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_cache.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_CACHE_H_ -#define ODP_IPSEC_CACHE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#include -#include - -/** - * 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 deleted file mode 100644 index 8d87051f5..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_fwd_db.c +++ /dev/null @@ -1,226 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* enable strtok */ -#define _POSIX_C_SOURCE 200112L - -#include -#include - -#include -#include - -#include - -/** - * 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 = DEFAULT_BUCKET_COUNT; - -/** Global pointer to fwd db */ -fwd_db_t *fwd_db; - -void 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); - if (hash_shm == ODP_SHM_INVALID) - ODPH_ABORT("Error: shared mem alloc failed.\n"); - flow_table = odp_shm_addr(hash_shm); - if (!flow_table) - ODPH_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); - - if (shm == ODP_SHM_INVALID) - ODPH_ABORT("Error: shared mem reserve failed.\n"); - - fwd_db = odp_shm_addr(shm); - - if (fwd_db == NULL) - ODPH_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 deleted file mode 100644 index f9f448aea..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_fwd_db.h +++ /dev/null @@ -1,198 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_FWD_DB_H_ -#define ODP_IPSEC_FWD_DB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#include - -#define OIF_LEN 32 - -/** - * Forwarding data base entry - */ - -typedef struct fwd_db_entry_s { - struct fwd_db_entry_s *next; /**< Next entry on list */ - char oif[OIF_LEN]; /**< Output interface name */ - odp_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*/ - ipsec_out_entry_t out_port; /**< Out interface of matching flow*/ -} flow_entry_t; - -/** - * Flow cache table bucket - */ -typedef struct { - odp_spinlock_t lock; /**< Bucket lock*/ - 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 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 flow_entry_t *route_flow_lookup_in_bucket(uint32_t sip, - uint32_t dip, - void *bucket) -{ - 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 route_flow_insert_in_bucket(flow_entry_t *flow, - void *bucket) -{ - flow_entry_t *temp; - flow_bucket_t *bkt = (flow_bucket_t *)bucket; - - if (!flow) { - ODPH_ERR("Invalid flow entry passed\n"); - return; - } - - LOCK(&bkt->lock); - /*Check that entry already exist or not*/ - temp = 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 deleted file mode 100644 index 81c14999e..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_misc.h +++ /dev/null @@ -1,366 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_MISC_H_ -#define ODP_IPSEC_MISC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -#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 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 DEFAULT_BUCKET_COUNT 1024 - -/**< Number of bits represented 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*/ -} ipsec_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_AES_CBC) && - (KEY_BITS_AES == key_bits_in)) - key->length = key_bits_in / 8; - } else { - if ((alg->u.auth == ODP_AUTH_ALG_MD5_HMAC) && - (KEY_BITS_MD5_96 == key_bits_in)) - key->length = key_bits_in / 8; - if ((alg->u.auth == 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_HMAC) && - (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); -} - -#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 deleted file mode 100644 index f61fd34db..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_sa_db.c +++ /dev/null @@ -1,365 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* enable strtok */ -#define _POSIX_C_SOURCE 200112L - -#include -#include - -#include -#include - -#include - -/** Global pointer to sa db */ -static sa_db_t *sa_db; - -/** Global pointer to tun db */ -static tun_db_t *tun_db; - -void init_sa_db(void) -{ - odp_shm_t shm; - - shm = odp_shm_reserve("shm_sa_db", - sizeof(sa_db_t), - ODP_CACHE_LINE_SIZE, - 0); - - if (shm == ODP_SHM_INVALID) - ODPH_ABORT("Error: shared mem reserve failed.\n"); - - sa_db = odp_shm_addr(shm); - - if (sa_db == NULL) - ODPH_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); - - if (shm == ODP_SHM_INVALID) - ODPH_ABORT("Error: shared mem reserve failed.\n"); - - tun_db = odp_shm_addr(shm); - - if (!tun_db) - ODPH_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_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_HMAC; - } else if (0 == strcmp(token, "sha1")) { - entry->alg.u.auth = - ODP_AUTH_ALG_SHA1_HMAC; - } else if (0 == strcmp(token, "sha256")) { - entry->alg.u.auth = - ODP_AUTH_ALG_SHA256_HMAC; - } 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 deleted file mode 100644 index f004028a7..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_sa_db.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_SA_DB_H_ -#define ODP_IPSEC_SA_DB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * 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 deleted file mode 100644 index ac8aa148e..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_sp_db.c +++ /dev/null @@ -1,167 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* enable strtok */ -#define _POSIX_C_SOURCE 200112L - -#include -#include - -#include -#include - -#include - -/** Global pointer to sp db */ -sp_db_t *sp_db; - -void init_sp_db(void) -{ - odp_shm_t shm; - - shm = odp_shm_reserve("shm_sp_db", - sizeof(sp_db_t), - ODP_CACHE_LINE_SIZE, - 0); - - if (shm == ODP_SHM_INVALID) - ODPH_ABORT("Error: shared mem reserve failed.\n"); - - sp_db = odp_shm_addr(shm); - - if (sp_db == NULL) - ODPH_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 deleted file mode 100644 index ac14f0dcb..000000000 --- a/example/ipsec_offload/odp_ipsec_offload_sp_db.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2017-2018, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ODP_IPSEC_SP_DB_H_ -#define ODP_IPSEC_SP_DB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * Security Policy (SP) data base entry - */ -typedef struct sp_db_entry_s { - struct sp_db_entry_s *next; /**< Next entry on list */ - ip_addr_range_t src_subnet; /**< Source IPv4 subnet/range */ - ip_addr_range_t dst_subnet; /**< Destination IPv4 subnet/range */ - odp_bool_t input; /**< Direction when applied */ - odp_bool_t esp; /**< Enable cipher (ESP) */ - odp_bool_t ah; /**< Enable authentication (AH) */ -} sp_db_entry_t; - -/** - * Security Policy (SP) data base global structure - */ -typedef struct sp_db_s { - uint32_t index; /**< Index of next available entry */ - sp_db_entry_t *list; /**< List of active entries */ - sp_db_entry_t array[MAX_DB]; /**< Entry storage */ -} sp_db_t; - -/** Global pointer to sp db */ -extern sp_db_t *sp_db; - -/** Initialize SP database global control structure */ -void init_sp_db(void); - -/** - * Create an SP DB entry - * - * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|both)" - * - * @param input Pointer to 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.sh b/example/ipsec_offload/run_left.sh deleted file mode 100755 index 58986a2f3..000000000 --- a/example/ipsec_offload/run_left.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/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.sh b/example/ipsec_offload/run_right.sh deleted file mode 100755 index d49aa1948..000000000 --- a/example/ipsec_offload/run_right.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/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 a3cc1ddbe..a1668e2b3 100644 --- a/example/m4/configure.m4 +++ b/example/m4/configure.m4 @@ -26,7 +26,6 @@ AC_CONFIG_FILES([example/classifier/Makefile example/ipsec_api/Makefile example/ipsec_crypto/Makefile example/ipfragreass/Makefile - example/ipsec_offload/Makefile example/l2fwd_simple/Makefile example/l3fwd/Makefile example/packet/Makefile -- cgit v1.2.3 From b0470792a68fa0fa1b7e2eaeedc721c1e9fc65cc Mon Sep 17 00:00:00 2001 From: Aakash Sasidharan Date: Mon, 25 Jan 2021 05:40:34 +0000 Subject: helper: ipsec: add algorithm check function Add IPSEC check function to see whether a requested algorithm configuration is supported by the platform. Signed-off-by: Aakash Sasidharan Reviewed-by: Janne Peltonen --- helper/Makefile.am | 1 + helper/include/odp/helper/ipsec.h | 23 ++++++ helper/ipsec.c | 163 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 helper/ipsec.c diff --git a/helper/Makefile.am b/helper/Makefile.am index e87b16c77..8c1c0ffc5 100644 --- a/helper/Makefile.am +++ b/helper/Makefile.am @@ -54,6 +54,7 @@ __LIB__libodphelper_la_SOURCES = \ lineartable.c \ cuckootable.c \ iplookuptable.c \ + ipsec.c \ threads.c \ version.c diff --git a/helper/include/odp/helper/ipsec.h b/helper/include/odp/helper/ipsec.h index d506d2a4d..66bed5399 100644 --- a/helper/include/odp/helper/ipsec.h +++ b/helper/include/odp/helper/ipsec.h @@ -70,6 +70,29 @@ typedef struct ODP_PACKED { ODP_STATIC_ASSERT(sizeof(odph_ahhdr_t) == ODPH_AHHDR_LEN, "ODPH_AHHDR_T__SIZE_ERROR"); +/** + * Check IPSEC algorithm support + * + * Based on the capabilities exposed by the ODP implementation, check whether + * the specified IPSEC algorithm configuration is supported by the + * implementation. The caller provides the IPSEC capability structure as an + * argument to the helper function. + * + * @param capa IPSEC capability structure + * @param cipher_alg Cipher algorithm + * @param cipher_key_len Length of cipher key in bytes + * @param auth_alg Authentication algorithm + * @param auth_key_len Length of authentication key in bytes + * + * @retval 0 on success + * @retval <0 on failure + */ +int odph_ipsec_alg_check(odp_ipsec_capability_t capa, + odp_cipher_alg_t cipher_alg, + uint32_t cipher_key_len, + odp_auth_alg_t auth_alg, + uint32_t auth_key_len); + /** * @} */ diff --git a/helper/ipsec.c b/helper/ipsec.c new file mode 100644 index 000000000..e2d24840e --- /dev/null +++ b/helper/ipsec.c @@ -0,0 +1,163 @@ +/* Copyright (c) 2017-2018, Linaro Limited + * Copyright (c) 2020 Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +int odph_ipsec_alg_check(odp_ipsec_capability_t capa, + odp_cipher_alg_t cipher_alg, + uint32_t cipher_key_len, + odp_auth_alg_t auth_alg, + uint32_t auth_key_len) +{ + int i, num, max_capa; + odp_bool_t found; + + /* Check whether requested cipher algorithm is supported */ + switch (cipher_alg) { + case ODP_CIPHER_ALG_NULL: + if (!capa.ciphers.bit.null) + return -1; + break; + case ODP_CIPHER_ALG_DES: + if (!capa.ciphers.bit.des) + return -1; + break; + case ODP_CIPHER_ALG_3DES_CBC: + if (!capa.ciphers.bit.trides_cbc) + return -1; + break; + case ODP_CIPHER_ALG_AES_CBC: + if (!capa.ciphers.bit.aes_cbc) + return -1; + break; + case ODP_CIPHER_ALG_AES_CTR: + if (!capa.ciphers.bit.aes_ctr) + return -1; + break; + case ODP_CIPHER_ALG_AES_GCM: + if (!capa.ciphers.bit.aes_gcm) + return -1; + break; + case ODP_CIPHER_ALG_AES_CCM: + if (!capa.ciphers.bit.aes_ccm) + return -1; + break; + case ODP_CIPHER_ALG_CHACHA20_POLY1305: + if (!capa.ciphers.bit.chacha20_poly1305) + return -1; + break; + default: + ODPH_DBG("Unsupported cipher algorithm\n"); + return -1; + } + + /* Check whether requested auth algorithm is supported */ + switch (auth_alg) { + case ODP_AUTH_ALG_NULL: + if (!capa.auths.bit.null) + return -1; + break; + case ODP_AUTH_ALG_MD5_HMAC: + if (!capa.auths.bit.md5_hmac) + return -1; + break; + case ODP_AUTH_ALG_SHA1_HMAC: + if (!capa.auths.bit.sha1_hmac) + return -1; + break; + case ODP_AUTH_ALG_SHA256_HMAC: + if (!capa.auths.bit.sha256_hmac) + return -1; + break; + case ODP_AUTH_ALG_SHA384_HMAC: + if (!capa.auths.bit.sha384_hmac) + return -1; + break; + case ODP_AUTH_ALG_SHA512_HMAC: + if (!capa.auths.bit.sha512_hmac) + return -1; + break; + case ODP_AUTH_ALG_AES_XCBC_MAC: + if (!capa.auths.bit.aes_xcbc_mac) + return -1; + break; + case ODP_AUTH_ALG_AES_GCM: + if (!capa.auths.bit.aes_gcm) + return -1; + break; + case ODP_AUTH_ALG_AES_GMAC: + if (!capa.auths.bit.aes_gmac) + return -1; + break; + case ODP_AUTH_ALG_AES_CCM: + if (!capa.auths.bit.aes_ccm) + return -1; + break; + case ODP_AUTH_ALG_CHACHA20_POLY1305: + if (!capa.auths.bit.chacha20_poly1305) + return -1; + break; + default: + ODPH_DBG("Unsupported authentication algorithm\n"); + return -1; + } + + /* Check whether requested cipher key length is supported */ + max_capa = odp_crypto_cipher_capability(cipher_alg, NULL, 0); + if (max_capa <= 0) + return -1; + + odp_ipsec_cipher_capability_t cipher_capa[max_capa]; + + num = odp_ipsec_cipher_capability(cipher_alg, cipher_capa, max_capa); + if (num <= 0) { + ODPH_DBG("Could not get cipher capabilities\n"); + return -1; + } + + found = false; + for (i = 0; i < num; i++) { + if (cipher_capa[i].key_len == cipher_key_len) { + found = 1; + break; + } + } + + if (!found) { + ODPH_DBG("Unsupported key length\n"); + return -1; + } + + /* Check whether requested auth key length is supported */ + max_capa = odp_crypto_auth_capability(auth_alg, NULL, 0); + if (max_capa <= 0) + return max_capa; + + odp_ipsec_auth_capability_t auth_capa[max_capa]; + + num = odp_ipsec_auth_capability(auth_alg, auth_capa, max_capa); + if (num <= 0) { + ODPH_DBG("Could not get auth capabilities\n"); + return -1; + } + + found = false; + for (i = 0; i < num; i++) { + if (auth_capa[i].key_len == auth_key_len) { + found = 1; + break; + } + } + + if (!found) { + ODPH_DBG("Unsupported auth key length\n"); + return -1; + } + + return 0; +} -- cgit v1.2.3 From bd51314f711e4a3f2622f1a0f77ad8bf22409f81 Mon Sep 17 00:00:00 2001 From: Aakash Sasidharan Date: Mon, 25 Jan 2021 06:46:04 +0000 Subject: validation: ipsec: use algorithm check helper function To avoid code duplication in IPSEC applications, use algorithm check function introduced in the helper library. Signed-off-by: Aakash Sasidharan Reviewed-by: Janne Peltonen --- test/validation/api/ipsec/ipsec.c | 136 +------------------------------------- 1 file changed, 2 insertions(+), 134 deletions(-) diff --git a/test/validation/api/ipsec/ipsec.c b/test/validation/api/ipsec/ipsec.c index 8f53ecc41..43322e36c 100644 --- a/test/validation/api/ipsec/ipsec.c +++ b/test/validation/api/ipsec/ipsec.c @@ -118,8 +118,6 @@ static void pktio_stop(odp_pktio_t pktio) } } -#define MAX_ALG_CAPA 32 - int ipsec_check(odp_bool_t ah, odp_cipher_alg_t cipher, uint32_t cipher_bits, @@ -127,10 +125,6 @@ int ipsec_check(odp_bool_t ah, uint32_t auth_bits) { odp_ipsec_capability_t capa; - odp_ipsec_cipher_capability_t cipher_capa[MAX_ALG_CAPA]; - odp_ipsec_auth_capability_t auth_capa[MAX_ALG_CAPA]; - int i, num; - odp_bool_t found; if (odp_ipsec_capability(&capa) < 0) return ODP_TEST_INACTIVE; @@ -159,135 +153,9 @@ int ipsec_check(odp_bool_t ah, if (ah && (ODP_SUPPORT_NO == capa.proto_ah)) return ODP_TEST_INACTIVE; - /* Cipher algorithms */ - switch (cipher) { - case ODP_CIPHER_ALG_NULL: - if (!capa.ciphers.bit.null) - return ODP_TEST_INACTIVE; - break; - case ODP_CIPHER_ALG_DES: - if (!capa.ciphers.bit.des) - return ODP_TEST_INACTIVE; - break; - case ODP_CIPHER_ALG_3DES_CBC: - if (!capa.ciphers.bit.trides_cbc) - return ODP_TEST_INACTIVE; - break; - case ODP_CIPHER_ALG_AES_CBC: - if (!capa.ciphers.bit.aes_cbc) - return ODP_TEST_INACTIVE; - break; - case ODP_CIPHER_ALG_AES_CTR: - if (!capa.ciphers.bit.aes_ctr) - return ODP_TEST_INACTIVE; - break; - case ODP_CIPHER_ALG_AES_GCM: - if (!capa.ciphers.bit.aes_gcm) - return ODP_TEST_INACTIVE; - break; - case ODP_CIPHER_ALG_AES_CCM: - if (!capa.ciphers.bit.aes_ccm) - return ODP_TEST_INACTIVE; - break; - case ODP_CIPHER_ALG_CHACHA20_POLY1305: - if (!capa.ciphers.bit.chacha20_poly1305) - return ODP_TEST_INACTIVE; - break; - default: - fprintf(stderr, "Unsupported cipher algorithm\n"); - return ODP_TEST_INACTIVE; - } - - /* Authentication algorithms */ - switch (auth) { - case ODP_AUTH_ALG_NULL: - if (!capa.auths.bit.null) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_MD5_HMAC: - if (!capa.auths.bit.md5_hmac) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_SHA1_HMAC: - if (!capa.auths.bit.sha1_hmac) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_SHA256_HMAC: - if (!capa.auths.bit.sha256_hmac) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_SHA384_HMAC: - if (!capa.auths.bit.sha384_hmac) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_SHA512_HMAC: - if (!capa.auths.bit.sha512_hmac) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_AES_XCBC_MAC: - if (!capa.auths.bit.aes_xcbc_mac) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_AES_GCM: - if (!capa.auths.bit.aes_gcm) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_AES_GMAC: - if (!capa.auths.bit.aes_gmac) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_AES_CCM: - if (!capa.auths.bit.aes_ccm) - return ODP_TEST_INACTIVE; - break; - case ODP_AUTH_ALG_CHACHA20_POLY1305: - if (!capa.auths.bit.chacha20_poly1305) - return ODP_TEST_INACTIVE; - break; - default: - fprintf(stderr, "Unsupported authentication algorithm\n"); - return ODP_TEST_INACTIVE; - } - - num = odp_ipsec_cipher_capability(cipher, cipher_capa, MAX_ALG_CAPA); - if (num <= 0) { - fprintf(stderr, "Wrong cipher capabilities\n"); + if (odph_ipsec_alg_check(capa, cipher, cipher_bits / 8, auth, + auth_bits / 8) < 0) return ODP_TEST_INACTIVE; - } - - /* Search for the test case */ - found = false; - for (i = 0; i < num; i++) { - if (cipher_capa[i].key_len == cipher_bits / 8) { - found = 1; - break; - } - } - - if (!found) { - fprintf(stderr, "Unsupported key length\n"); - return ODP_TEST_INACTIVE; - } - - num = odp_ipsec_auth_capability(auth, auth_capa, MAX_ALG_CAPA); - if (num <= 0) { - fprintf(stderr, "Wrong auth capabilities\n"); - return ODP_TEST_INACTIVE; - } - - /* Search for the test case */ - found = false; - for (i = 0; i < num; i++) { - if (auth_capa[i].key_len == auth_bits / 8) { - found = 1; - break; - } - } - - if (!found) { - fprintf(stderr, "Unsupported auth key length\n"); - return ODP_TEST_INACTIVE; - } return ODP_TEST_ACTIVE; } -- cgit v1.2.3 From 64b5a48e7b850b48a61968d082bb16c22d48fa3f Mon Sep 17 00:00:00 2001 From: Aakash Sasidharan Date: Wed, 16 Dec 2020 12:10:01 +0000 Subject: test: ipsec: add capability checks Run the tests only for the configurations supported by the platform. Signed-off-by: Aakash Sasidharan Reviewed-by: Janne Peltonen --- test/performance/odp_ipsec.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/performance/odp_ipsec.c b/test/performance/odp_ipsec.c index 37a30a3ba..2e283a63b 100644 --- a/test/performance/odp_ipsec.c +++ b/test/performance/odp_ipsec.c @@ -792,11 +792,32 @@ static int run_measure_one_config(ipsec_args_t *cargs, ipsec_alg_config_t *config) { - odp_ipsec_sa_t sa; - int rc = 0; unsigned int num_payloads = global_num_payloads; unsigned int *payloads = global_payloads; + odp_ipsec_capability_t capa; + odp_ipsec_sa_t sa; unsigned int i; + int rc = 0; + + if (odp_ipsec_capability(&capa) < 0) { + app_err("IPSEC capability call failed.\n"); + return -1; + } + + if (cargs->ah && (ODP_SUPPORT_NO == capa.proto_ah)) { + app_err("IPSEC AH protocol not supported.\n"); + return -1; + } + + rc = odph_ipsec_alg_check(capa, config->crypto.cipher_alg, + config->crypto.cipher_key.length, + config->crypto.auth_alg, + config->crypto.auth_key.length); + + if (rc) { + printf(" => %s skipped\n\n", config->name); + return 0; + } sa = create_sa_from_config(config, cargs); if (sa == ODP_IPSEC_SA_INVALID) { -- cgit v1.2.3 From 7285541a98c2a81e5f25def52483e48acb400821 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 8 Oct 2020 16:03:02 +0300 Subject: api: packet: add packet LSO metadata Added packet metadata calls that are used when LSO segmentation is requested for a packet. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo Reviewed-by: Yuri Tolstov --- include/odp/api/spec/packet.h | 105 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/include/odp/api/spec/packet.h b/include/odp/api/spec/packet.h index 44fc75924..3810c279a 100644 --- a/include/odp/api/spec/packet.h +++ b/include/odp/api/spec/packet.h @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -2035,6 +2036,110 @@ void odp_packet_shaper_len_adjust_set(odp_packet_t pkt, int8_t adj); */ uint64_t odp_packet_cls_mark(odp_packet_t pkt); +/** + * LSO options + */ +typedef struct odp_packet_lso_opt_t { + /** LSO profile handle + * + * The selected LSO profile specifies details of the segmentation operation to be done. + * Depending on LSO profile options, additional metadata (e.g. L3/L4 protocol header + * offsets) may need to be set on the packet. See LSO documentation + * (e.g. odp_pktout_send_lso() and odp_lso_protocol_t) for additional metadata + * requirements. + */ + odp_lso_profile_t lso_profile; + + /** LSO payload offset + * + * LSO operation considers packet data before 'payload_offset' as + * protocol headers and copies those in front of every created segment. It will modify + * protocol headers according to the LSO profile before segment transmission. + * + * When stored into a packet, this offset can be read with odp_packet_payload_offset() and + * modified with odp_packet_payload_offset_set(). + */ + uint32_t payload_offset; + + /** Maximum payload length in an LSO segment + * + * Max_payload_len parameter defines the maximum number of payload bytes in each + * created segment. Depending on the implementation, segments with less payload may be + * created. However, this value is used typically to divide packet payload evenly over + * all segments except the last one, which contains the remaining payload bytes. + */ + uint32_t max_payload_len; + +} odp_packet_lso_opt_t; + +/** + * Request Large Send Offload (LSO) for a packet + * + * Setup packet metadata which requests LSO segmentation to be performed during packet output. + * The selected LSO profile specifies details of the segmentation operation to be done. Depending on + * LSO profile options, additional metadata (e.g. L3/L4 protocol header offsets) may need to be + * set on the packet. + * + * @param pkt Packet handle + * @param lso_opt LSO options + * + * @retval 0 On success + * @retval <0 On failure + */ +int odp_packet_lso_request(odp_packet_t pkt, const odp_packet_lso_opt_t *lso_opt); + +/** + * Clear LSO request from a packet + * + * Clears packet metadata not to request LSO segmentation. + * + * @param pkt Packet handle + */ +void odp_packet_lso_request_clr(odp_packet_t pkt); + +/** + * Check if LSO is requested for the packet + * + * @param pkt Packet handle + * + * @retval non-zero LSO is requested + * @retval 0 LSO is not requested + */ +int odp_packet_has_lso_request(odp_packet_t pkt); + +/** + * Payload data offset + * + * Returns offset to the start of payload data. Packet data before this offset is considered as + * protocol headers. The offset is calculated from the current odp_packet_data() position in bytes. + * Data start position updating functions (e.g. odp_packet_push_head()) do not modify the offset, + * but user sets a new value when needed. + * + * Packet parsing does not set this offset. Initial offset value is undefined. Application may + * utilize the offset for internal purposes or when requesting LSO segmentation for the packet. + * + * @param pkt Packet handle + * + * @return Payload data offset + * @retval ODP_PACKET_OFFSET_INVALID Payload data offset has not been set + */ +uint32_t odp_packet_payload_offset(odp_packet_t pkt); + +/** + * Set payload data start offset + * + * Set offset to the start of payload data. The offset is calculated from the current + * odp_packet_data() position in bytes. Offset must not exceed packet data length. Offset is not + * modified on an error. + * + * @param pkt Packet handle + * @param offset Payload data start offset (0 ... odp_packet_len()-1) or ODP_PACKET_OFFSET_INVALID + * + * @retval 0 on success + * @retval <0 on failure + */ +int odp_packet_payload_offset_set(odp_packet_t pkt, uint32_t offset); + /* * * Packet vector handling routines -- cgit v1.2.3 From bf56a32a51250333302879b72a5fae6d687ddf68 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Mon, 15 Jun 2020 17:37:20 +0300 Subject: api: pktio: add packet send with LSO Added new odp_pktout_send_lso() function, which offloads packet segmentation during packet output to Large Send Offload (LSO) hardware. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo Reviewed-by: Yuri Tolstov --- include/odp/api/spec/packet_io.h | 267 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h index 940b712fa..a6369acdf 100644 --- a/include/odp/api/spec/packet_io.h +++ b/include/odp/api/spec/packet_io.h @@ -56,11 +56,21 @@ extern "C" { * Direct packet output queue handle */ +/** + * @typedef odp_lso_profile_t + * LSO profile handle + */ + /** * @def ODP_PKTIO_INVALID * Invalid packet IO handle */ +/** + * @def ODP_LSO_PROFILE_INVALID + * Invalid LSO profile handle + */ + /** * @def ODP_PKTIO_MACADDR_MAXSIZE * Minimum size of output buffer for odp_pktio_mac_addr() @@ -594,6 +604,18 @@ typedef struct odp_pktio_config_t { */ odp_bool_t outbound_ipsec; + /** Enable Large Send Offload (LSO) + * + * LSO operation cannot be combined with IPSEC or Traffic Manager (ODP_PKTOUT_MODE_TM) on + * packet output. + * + * 0: Application will not use LSO (default) + * 1: Application will use LSO + * + * @see odp_pktout_send_lso() + */ + odp_bool_t enable_lso; + } odp_pktio_config_t; /** @@ -617,6 +639,131 @@ typedef union odp_pktio_set_op_t { uint32_t all_bits; } odp_pktio_set_op_t; +/** Maximum number of custom LSO fields supported by ODP API */ +#define ODP_LSO_MAX_CUSTOM 8 + +/** LSO custom modification options */ +typedef enum odp_lso_modify_t { + /** Add current segment number. Numbering starts from zero. */ + ODP_LSO_ADD_SEGMENT_NUM = 0x1, + + /** Add number of payload bytes in the segment */ + ODP_LSO_ADD_PAYLOAD_LEN = 0x2, + + /** Add number of payload bytes in all previous segments */ + ODP_LSO_ADD_PAYLOAD_OFFSET = 0x4 + +} odp_lso_modify_t; + +/** LSO protocol options + * + * An LSO operation may perform segmentation on these protocols. + */ +typedef enum odp_lso_protocol_t { + /** Protocol not selected. */ + ODP_LSO_PROTO_NONE = 0, + + /** Custom protocol. LSO performs only custom field updates to the packet headers. */ + ODP_LSO_PROTO_CUSTOM, + + /** LSO performs IPv4 fragmentation. + * + * IP header length and checksum fields are updated. IP fragmentation related fields are + * filled and IPv4 Identification field value is copied from the original packet. */ + ODP_LSO_PROTO_IPV4, + + /** LSO performs IPv6 fragmentation. */ + ODP_LSO_PROTO_IPV6, + + /** LSO performs TCP segmentation on top of IPv4. + * + * IP header length and checksum fields are updated. IP fragmentation is not performed + * and IPv4 Don't Fragment bit is not set. Unique IPv4 Identification field values + * are generated. Those are usually increments of the IPv4 ID field value in the packet. + */ + ODP_LSO_PROTO_TCP_IPV4, + + /** LSO performs TCP segmentation on top of IPv6. */ + ODP_LSO_PROTO_TCP_IPV6, + + /** LSO performs SCTP segmentation on top of IPv4. */ + ODP_LSO_PROTO_SCTP_IPV4, + + /** LSO performs SCTP segmentation on top of IPv6. */ + ODP_LSO_PROTO_SCTP_IPV6 + +} odp_lso_protocol_t; + +/** Large Send Offload (LSO) capabilities */ +typedef struct odp_lso_capability_t { + /** Maximum number of LSO profiles. When zero, LSO is not supported. */ + uint32_t max_profiles; + + /** Maximum number of LSO profiles per packet IO interface. When zero, LSO is not + * supported by the interface. */ + uint32_t max_profiles_per_pktio; + + /** Maximum number of segments in an input packet. When one, LSO operation accepts only + * non-segmented packets as input. */ + uint32_t max_packet_segments; + + /** Maximum number of segments an LSO operation may create. This implies that + * the maximum supported input packet payload size for an LSO operation is + * max_segments * max_payload_len bytes. */ + uint32_t max_segments; + + /** Maximum payload length per an LSO generated packet (in bytes). This is the maximum value + * for max_payload_len in odp_packet_lso_opt_t. */ + uint32_t max_payload_len; + + /** Maximum supported offset to the packet payload (in bytes). This is the maximum value + * for payload_offset in odp_packet_lso_opt_t. */ + uint32_t max_payload_offset; + + /** Supported LSO custom modification options */ + struct { + /** ODP_LSO_ADD_SEGMENT_NUM support */ + uint16_t add_segment_num:1; + + /** ODP_LSO_ADD_PAYLOAD_LEN support */ + uint16_t add_payload_len:1; + + /** ODP_LSO_ADD_PAYLOAD_OFFSET support */ + uint16_t add_payload_offset:1; + + } mod_op; + + /** Maximum number of custom fields supported per LSO profile. When zero, custom + * fields are not supported. */ + uint8_t max_num_custom; + + /** Supported LSO protocol options */ + struct { + /** ODP_LSO_PROTO_CUSTOM support */ + uint32_t custom:1; + + /** ODP_LSO_PROTO_IPV4 support */ + uint32_t ipv4:1; + + /** ODP_LSO_PROTO_IPV6 support */ + uint32_t ipv6:1; + + /** ODP_LSO_PROTO_TCP_IPV4 support */ + uint32_t tcp_ipv4:1; + + /** ODP_LSO_PROTO_TCP_IPV6 support */ + uint32_t tcp_ipv6:1; + + /** ODP_LSO_PROTO_SCTP_IPV4 support */ + uint32_t sctp_ipv4:1; + + /** ODP_LSO_PROTO_SCTP_IPV6 support */ + uint32_t sctp_ipv6:1; + + } proto; + +} odp_lso_capability_t; + /** * Packet input vector capabilities */ @@ -673,6 +820,9 @@ typedef struct odp_pktio_capability_t { /** Packet input vector capability */ odp_pktin_vector_capability_t vector; + /** LSO capabilities */ + odp_lso_capability_t lso; + } odp_pktio_capability_t; /** @@ -1095,6 +1245,123 @@ uint64_t odp_pktin_wait_time(uint64_t nsec); int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[], int num); +/** + * LSO profile parameters + */ +typedef struct odp_lso_profile_param_t { + /** + * Segmentation protocol + * + * Selects on which protocol LSO operation performs segmentation (e.g. IP fragmentation vs. + * TCP segmentation). When ODP_LSO_PROTO_CUSTOM is selected, only custom field + * modifications are performed. The default value is ODP_LSO_PROTO_NONE. Check LSO + * capability for supported protocols. + */ + odp_lso_protocol_t lso_proto; + + /** + * Custom fields + * + * Set lso_proto to ODP_LSO_PROTO_CUSTOM when using custom fields. Fields are defined + * in the same order they appear in the packet. + */ + struct { + /** Custom field to be modified by LSO */ + struct { + /** Field modify operation. Selects how value of the field is modified + * from its original value during segmentation. Field value is assumed + * to be in network (big endian) byte order. */ + odp_lso_modify_t mod_op; + + /** Field offset in bytes from packet start */ + uint32_t offset; + + /** Field size in bytes. Valid values are 1, 2, 4, and 8 bytes. */ + uint8_t size; + + } field[ODP_LSO_MAX_CUSTOM]; + + /** Number of custom fields specified. The default value is 0. */ + uint8_t num_custom; + + } custom; + +} odp_lso_profile_param_t; + +/** + * Initialize LSO profile parameters + * + * Initialize an odp_lso_profile_param_t to its default values for all fields. + * + * @param param Address of the odp_lso_profile_param_t to be initialized + */ +void odp_lso_profile_param_init(odp_lso_profile_param_t *param); + +/** + * Create LSO profile + * + * LSO profile defines the set of segmentation operations to be performed to a packet. LSO profiles + * are created before the packet IO interface is started (after odp_pktio_config() and before + * odp_pktio_start()). + * + * See odp_lso_capability_t for maximum number of profiles supported and other LSO capabilities. + * + * @param pktio Packet IO interface which is used with this LSO profile + * @param param LSO profile parameters + * + * @return LSO profile handle + * @retval ODP_LSO_PROFILE_INVALID on failure + */ +odp_lso_profile_t odp_lso_profile_create(odp_pktio_t pktio, const odp_lso_profile_param_t *param); + +/** + * Destroy LSO profile + * + * LSO profiles can be destoyed only when the packet IO interface is not active (i.e. after it + * has been stopped). + * + * @param lso_profile LSO profile to be destroyed + * + * @retval 0 on success + * @retval <0 on failure + */ +int odp_lso_profile_destroy(odp_lso_profile_t lso_profile); + +/** + * Send packets with segmentation offload + * + * Like odp_pktout_send(), but splits a packet payload into 'max_payload_len' or smaller segments + * during output. Packet headers (before 'payload_offset') are copied into each segment and + * automatically modified before transmission. Header updates are based on segmentation protocol + * selection (odp_lso_profile_param_t::lso_proto) in LSO profile. Header checksums are updated + * after modifications. L3/L4 header modifications (see e.g. ODP_LSO_PROTO_TCP_IPV4) require that + * L3/L4 layer offsets in the packet are valid (see e.g. odp_packet_l3_offset()). + * + * In addition, custom field updates may be used to cover unsupported or proprietary protocols. + * Custom fields must not overlap with each other and can be used only when ODP_LSO_PROTO_CUSTOM + * is selected. + * + * Packets are processed and transmitted in the array order. Segments of each packet are transmitted + * in ascending order. + * + * When all packets share the same LSO options, usage of 'lso_opt' parameter may improve + * performance as a number of packet metadata writes/reads are avoided. Results are undefined if + * 'lso_opt' is NULL and a packet misses LSO options. + * + * Check LSO support level from packet IO capabilities (odp_pktio_capability_t). + * + * @param queue Packet output queue handle + * @param packet[] Array of packets to be LSO processed and sent + * @param num Number of packets + * @param lso_opt When set, LSO options to be used for all packets. When NULL, LSO options are + * read from each packet (see odp_packet_lso_request()). + * + * @return Number of packets successfully segmented (0 ... num) + * @retval <0 on failure + */ +int odp_pktout_send_lso(odp_pktout_queue_t queue, const odp_packet_t packet[], int num, + const odp_packet_lso_opt_t *lso_opt); + /** * MTU value of a packet IO interface * -- cgit v1.2.3 From f1b1cddf76e7a2d39c99322bff4ea8e1ac1a7981 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 9 Oct 2020 11:36:57 +0300 Subject: linux-gen: packet: ensure header size with static assert Ensure that buffer and packet header sizes do not accidentally grow to new cache lines when adding new struct fields. Removed comments about data alignment as those may not be always valid (e.g. 32 bit builds). Added debug prints for checking data alignment on the same offsets. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- platform/linux-generic/include/odp_buffer_internal.h | 5 +++++ platform/linux-generic/include/odp_packet_internal.h | 13 ++++++++----- platform/linux-generic/odp_pool.c | 11 ++++++----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/platform/linux-generic/include/odp_buffer_internal.h b/platform/linux-generic/include/odp_buffer_internal.h index 62caa776e..d2e3c808f 100644 --- a/platform/linux-generic/include/odp_buffer_internal.h +++ b/platform/linux-generic/include/odp_buffer_internal.h @@ -87,6 +87,11 @@ struct ODP_ALIGNED_CACHE odp_buffer_hdr_t { uint8_t data[0]; }; +/* Buffer header size is critical for performance. Ensure that it does not accidentally + * grow over cache line size. Note that ODP_ALIGNED_CACHE rounds up struct size to a multiple of + * ODP_CACHE_LINE_SIZE. */ +ODP_STATIC_ASSERT(sizeof(odp_buffer_hdr_t) <= ODP_CACHE_LINE_SIZE, "BUFFER_HDR_SIZE_ERROR"); + odp_event_type_t _odp_buffer_event_type(odp_buffer_t buf); void _odp_buffer_event_type_set(odp_buffer_t buf, int ev); diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h index 2a961893b..eba74cc49 100644 --- a/platform/linux-generic/include/odp_packet_internal.h +++ b/platform/linux-generic/include/odp_packet_internal.h @@ -81,11 +81,9 @@ ODP_STATIC_ASSERT(PKT_MAX_SEGS < UINT16_MAX, "PACKET_MAX_SEGS_ERROR"); * initialization requirements. */ typedef struct odp_packet_hdr_t { - /* Common buffer header */ + /* Common buffer header (cache line aligned) */ odp_buffer_hdr_t buf_hdr; - /* --- 64 bytes --- */ - /* Segment data start */ uint8_t *seg_data; @@ -112,8 +110,6 @@ typedef struct odp_packet_hdr_t { /* Event subtype */ int8_t subtype; - /* --- 128 bytes --- */ - /* Timestamp value */ odp_time_t timestamp; @@ -144,8 +140,15 @@ typedef struct odp_packet_hdr_t { /* Packet data storage */ uint8_t data[0]; + } odp_packet_hdr_t; +/* Packet header size is critical for performance. Ensure that it does not accidentally + * grow over 256 bytes when cache line size is 64 bytes (or less). With larger cache line sizes, + * the struct size is larger due to the odp_buffer_hdr_t alignment requirement. */ +ODP_STATIC_ASSERT(sizeof(odp_packet_hdr_t) <= 256 || ODP_CACHE_LINE_SIZE > 64, + "PACKET_HDR_SIZE_ERROR"); + /** * Return the packet header */ diff --git a/platform/linux-generic/odp_pool.c b/platform/linux-generic/odp_pool.c index 9e6530eb6..0b1d0a7f4 100644 --- a/platform/linux-generic/odp_pool.c +++ b/platform/linux-generic/odp_pool.c @@ -298,11 +298,12 @@ int _odp_pool_init_global(void) } ODP_DBG("\nPool init global\n"); - ODP_DBG(" odp_buffer_hdr_t size %zu\n", sizeof(odp_buffer_hdr_t)); - ODP_DBG(" odp_packet_hdr_t size %zu\n", sizeof(odp_packet_hdr_t)); - ODP_DBG(" odp_timeout_hdr_t size %zu\n", sizeof(odp_timeout_hdr_t)); - ODP_DBG(" odp_event_vector_hdr_t size %zu\n", sizeof(odp_event_vector_hdr_t)); - + ODP_DBG(" buffer_hdr_t size %zu\n", sizeof(odp_buffer_hdr_t)); + ODP_DBG(" packet_hdr_t size %zu\n", sizeof(odp_packet_hdr_t)); + ODP_DBG(" timeout_hdr_t size %zu\n", sizeof(odp_timeout_hdr_t)); + ODP_DBG(" event_vector_hdr_t size %zu\n", sizeof(odp_event_vector_hdr_t)); + ODP_DBG(" packet_hdr_t::seg_data offset %zu\n", offsetof(odp_packet_hdr_t, seg_data)); + ODP_DBG(" packet_hdr_t::timestamp offset %zu\n", offsetof(odp_packet_hdr_t, timestamp)); ODP_DBG("\n"); return 0; } -- cgit v1.2.3 From aedc4fb85e7e08c8772efc8791238d9bf8b8627e Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Tue, 3 Nov 2020 15:31:27 +0200 Subject: linux-gen: pktio: add lso types to ABI Added LSO type defitions to ABI files. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- include/odp/api/abi-default/packet_io.h | 6 ++++++ platform/linux-generic/include-abi/odp/api/abi/packet_io.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/include/odp/api/abi-default/packet_io.h b/include/odp/api/abi-default/packet_io.h index a97b574d7..d545b7074 100644 --- a/include/odp/api/abi-default/packet_io.h +++ b/include/odp/api/abi-default/packet_io.h @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -22,12 +23,16 @@ extern "C" { /** @internal Dummy type for strong typing */ typedef struct { char dummy; /**< @internal Dummy */ } _odp_abi_pktio_t; +/** @internal Dummy type for strong typing */ +typedef struct { char dummy; /**< @internal Dummy */ } _odp_abi_lso_profile_t; + /** @addtogroup odp_packet_io * Operations on a packet. * @{ */ typedef _odp_abi_pktio_t *odp_pktio_t; +typedef _odp_abi_lso_profile_t *odp_lso_profile_t; /** @internal */ typedef struct odp_pktin_queue_t { @@ -42,6 +47,7 @@ typedef struct odp_pktout_queue_t { } odp_pktout_queue_t; #define ODP_PKTIO_INVALID ((odp_pktio_t)0) +#define ODP_LSO_PROFILE_INVALID ((odp_lso_profile_t)0) #define ODP_PKTIO_MACADDR_MAXSIZE 16 diff --git a/platform/linux-generic/include-abi/odp/api/abi/packet_io.h b/platform/linux-generic/include-abi/odp/api/abi/packet_io.h index dcae53931..45f06912c 100644 --- a/platform/linux-generic/include-abi/odp/api/abi/packet_io.h +++ b/platform/linux-generic/include-abi/odp/api/abi/packet_io.h @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -27,6 +28,7 @@ extern "C" { */ typedef ODP_HANDLE_T(odp_pktio_t); +typedef ODP_HANDLE_T(odp_lso_profile_t); /** @internal */ typedef struct odp_pktin_queue_t { @@ -41,6 +43,7 @@ typedef struct odp_pktout_queue_t { } odp_pktout_queue_t; #define ODP_PKTIO_INVALID _odp_cast_scalar(odp_pktio_t, 0) +#define ODP_LSO_PROFILE_INVALID _odp_cast_scalar(odp_lso_profile_t, 0) #define ODP_PKTIO_MACADDR_MAXSIZE 16 -- cgit v1.2.3 From 2749003ce260da6d2df89477351ebf7d426f7e7a Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 9 Oct 2020 17:12:37 +0300 Subject: linux-gen: packet: implement LSO related metadata APIs Implement all packet metadata API for LSO usage except odp_packet_lso_request(), which will be added to odp_packet_io.c since it needs access to LSO profile. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- .../include/odp/api/plat/packet_inline_types.h | 8 ++-- .../linux-generic/include/odp_packet_internal.h | 9 ++++ platform/linux-generic/odp_packet.c | 56 ++++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/platform/linux-generic/include/odp/api/plat/packet_inline_types.h b/platform/linux-generic/include/odp/api/plat/packet_inline_types.h index ec7b1900e..9fd8a0ced 100644 --- a/platform/linux-generic/include/odp/api/plat/packet_inline_types.h +++ b/platform/linux-generic/include/odp/api/plat/packet_inline_types.h @@ -115,7 +115,7 @@ typedef union { uint32_t all_flags; struct { - uint32_t reserved1: 10; + uint32_t reserved1: 8; /* * Init flags @@ -125,6 +125,8 @@ typedef union { /* * Packet output flags */ + uint32_t lso: 1; /* LSO requested */ + uint32_t payload_off: 1; /* Payload offset is valid */ uint32_t l3_chksum_set: 1; /* L3 chksum bit is valid */ uint32_t l3_chksum: 1; /* L3 chksum override */ uint32_t l4_chksum_set: 1; /* L4 chksum bit is valid */ @@ -147,8 +149,8 @@ typedef union { /* Flag groups */ struct { - uint32_t reserved2: 10; - uint32_t other: 14; /* All other flags */ + uint32_t reserved2: 8; + uint32_t other: 16; /* All other flags */ uint32_t error: 8; /* All error flags */ } all; diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h index eba74cc49..8349df43a 100644 --- a/platform/linux-generic/include/odp_packet_internal.h +++ b/platform/linux-generic/include/odp_packet_internal.h @@ -125,6 +125,15 @@ typedef struct odp_packet_hdr_t { /* Classifier handle index */ uint16_t cos; + /* Offset to payload start */ + uint16_t payload_offset; + + /* Max payload size in a LSO segment */ + uint16_t lso_max_payload; + + /* LSO profile index */ + uint8_t lso_profile_idx; + union { struct { /* Result for crypto packet op */ diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c index dd783acd9..2fe7fe67d 100644 --- a/platform/linux-generic/odp_packet.c +++ b/platform/linux-generic/odp_packet.c @@ -175,6 +175,14 @@ static inline void packet_seg_copy_md(odp_packet_hdr_t *dst, dst->flow_hash = src->flow_hash; dst->timestamp = src->timestamp; + if (src->p.flags.lso) { + dst->lso_max_payload = src->lso_max_payload; + dst->lso_profile_idx = src->lso_profile_idx; + } + + if (src->p.flags.payload_off) + dst->payload_offset = src->payload_offset; + /* buffer header side packet metadata */ dst->buf_hdr.user_ptr = src->buf_hdr.user_ptr; dst->buf_hdr.uarea_addr = src->buf_hdr.uarea_addr; @@ -1754,6 +1762,20 @@ int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt) src_uarea_size); } + if (srchdr->p.input_flags.flow_hash) + dsthdr->flow_hash = srchdr->flow_hash; + + if (srchdr->p.input_flags.timestamp) + dsthdr->timestamp = srchdr->timestamp; + + if (srchdr->p.flags.lso) { + dsthdr->lso_max_payload = srchdr->lso_max_payload; + dsthdr->lso_profile_idx = srchdr->lso_profile_idx; + } + + if (srchdr->p.flags.payload_off) + dsthdr->payload_offset = srchdr->payload_offset; + copy_packet_parser_metadata(srchdr, dsthdr); /* Metadata copied, but return indication of whether the packet @@ -2888,3 +2910,37 @@ void odp_packet_ts_request(odp_packet_t pkt, int enable) pkt_hdr->p.flags.ts_set = !!enable; } + +void odp_packet_lso_request_clr(odp_packet_t pkt) +{ + odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); + + pkt_hdr->p.flags.lso = 0; +} + +int odp_packet_has_lso_request(odp_packet_t pkt) +{ + odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); + + return pkt_hdr->p.flags.lso; +} + +uint32_t odp_packet_payload_offset(odp_packet_t pkt) +{ + odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); + + if (pkt_hdr->p.flags.payload_off) + return pkt_hdr->payload_offset; + + return ODP_PACKET_OFFSET_INVALID; +} + +int odp_packet_payload_offset_set(odp_packet_t pkt, uint32_t offset) +{ + odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); + + pkt_hdr->p.flags.payload_off = 1; + pkt_hdr->payload_offset = offset; + + return 0; +} -- cgit v1.2.3 From e1afee9e0d0a6582542cda5da6756302f0121f77 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Tue, 3 Nov 2020 15:33:26 +0200 Subject: linux-gen: pktio: implement LSO API Implement new LSO functions. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- .../linux-generic/include/odp_packet_io_internal.h | 14 + platform/linux-generic/odp_packet_io.c | 367 +++++++++++++++++++++ 2 files changed, 381 insertions(+) diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 9254fad3c..afd36681a 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -38,6 +38,10 @@ extern "C" { #include #define PKTIO_MAX_QUEUES 64 +#define PKTIO_LSO_PROFILES 16 +#define PKTIO_LSO_MAX_PAYLOAD_OFFSET 128 +#define PKTIO_LSO_MAX_SEGMENTS 8 +ODP_STATIC_ASSERT(PKTIO_LSO_PROFILES < UINT8_MAX, "PKTIO_LSO_PROFILES_ERROR"); #define PKTIO_NAME_LEN 256 @@ -150,6 +154,13 @@ typedef union { uint8_t pad[ROUNDUP_CACHE_LINE(sizeof(struct pktio_entry))]; } pktio_entry_t; +typedef struct { + odp_lso_profile_param_t param; + int used; + uint8_t index; + +} lso_profile_t; + /* Global variables */ typedef struct { odp_spinlock_t lock; @@ -162,6 +173,9 @@ typedef struct { pktio_entry_t entries[ODP_CONFIG_PKTIO_ENTRIES]; + lso_profile_t lso_profile[PKTIO_LSO_PROFILES]; + int num_lso_profiles; + } pktio_global_t; typedef struct pktio_if_ops { diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index e46da443b..88e6c0dcf 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -1726,6 +1726,13 @@ int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa) ret = single_capability(capa); if (ret == 0) { + uint32_t mtu = pktio_mtu(pktio); + + if (mtu == 0) { + ODP_DBG("MTU query failed: %s\n", entry->s.name); + return -1; + } + /* The same parser is used for all pktios */ capa->config.parser.layer = ODP_PROTO_LAYER_ALL; /* Header skip is not supported */ @@ -1734,6 +1741,17 @@ int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa) * we can report that it is supported. */ capa->config.pktout.bit.no_packet_refs = 1; + + /* LSO implementation is common to all pktios */ + capa->lso.max_profiles = PKTIO_LSO_PROFILES; + capa->lso.max_profiles_per_pktio = PKTIO_LSO_PROFILES; + capa->lso.max_packet_segments = PKT_MAX_SEGS; + capa->lso.max_segments = PKTIO_LSO_MAX_SEGMENTS; + capa->lso.max_payload_len = mtu - PKTIO_LSO_MAX_PAYLOAD_OFFSET; + capa->lso.max_payload_offset = PKTIO_LSO_MAX_PAYLOAD_OFFSET; + capa->lso.max_num_custom = ODP_LSO_MAX_CUSTOM; + capa->lso.proto.custom = 1; + capa->lso.mod_op.add_segment_num = 1; } /* Packet vector generation is common for all pktio types */ @@ -2472,3 +2490,352 @@ int odp_pktout_ts_read(odp_pktio_t hdl, odp_time_t *ts) ts->u64 = ts_val; return 0; } + +void odp_lso_profile_param_init(odp_lso_profile_param_t *param) +{ + memset(param, 0, sizeof(odp_lso_profile_param_t)); + + param->lso_proto = ODP_LSO_PROTO_NONE; +} + +odp_lso_profile_t odp_lso_profile_create(odp_pktio_t pktio, const odp_lso_profile_param_t *param) +{ + uint32_t i, num_custom, mod_op, offset, size; + lso_profile_t *lso_prof = NULL; + (void)pktio; + + /* Currently only custom implemented */ + if (param->lso_proto != ODP_LSO_PROTO_CUSTOM) { + ODP_ERR("Protocol not supported\n"); + return ODP_LSO_PROFILE_INVALID; + } + + num_custom = param->custom.num_custom; + if (num_custom > ODP_LSO_MAX_CUSTOM) { + ODP_ERR("Too many custom fields\n"); + return ODP_LSO_PROFILE_INVALID; + } + + for (i = 0; i < num_custom; i++) { + mod_op = param->custom.field[i].mod_op; + offset = param->custom.field[i].offset; + size = param->custom.field[i].size; + + if (offset > PKTIO_LSO_MAX_PAYLOAD_OFFSET) { + ODP_ERR("Too large custom field offset %u\n", offset); + return ODP_LSO_PROFILE_INVALID; + } + + /* Currently only segment number supported */ + if (mod_op != ODP_LSO_ADD_SEGMENT_NUM) { + ODP_ERR("Custom modify operation %u not supported\n", mod_op); + return ODP_LSO_PROFILE_INVALID; + } + + if (size != 1 && size != 2 && size != 4 && size != 8) { + ODP_ERR("Bad custom field size %u\n", size); + return ODP_LSO_PROFILE_INVALID; + } + } + + odp_spinlock_lock(&pktio_global->lock); + + if (pktio_global->num_lso_profiles >= PKTIO_LSO_PROFILES) { + odp_spinlock_unlock(&pktio_global->lock); + ODP_ERR("All LSO profiles used already: %u\n", PKTIO_LSO_PROFILES); + return ODP_LSO_PROFILE_INVALID; + } + + for (i = 0; i < PKTIO_LSO_PROFILES; i++) { + if (pktio_global->lso_profile[i].used == 0) { + lso_prof = &pktio_global->lso_profile[i]; + lso_prof->used = 1; + pktio_global->num_lso_profiles++; + break; + } + } + + odp_spinlock_unlock(&pktio_global->lock); + + if (lso_prof == NULL) { + ODP_ERR("Did not find free LSO profile\n"); + return ODP_LSO_PROFILE_INVALID; + } + + lso_prof->param = *param; + lso_prof->index = i; + + return (odp_lso_profile_t)(uintptr_t)lso_prof; +} + +static inline odp_lso_profile_t lso_profile_from_idx(uint8_t idx) +{ + return (odp_lso_profile_t)(uintptr_t)&pktio_global->lso_profile[idx]; +} + +static inline lso_profile_t *lso_profile_ptr(odp_lso_profile_t handle) +{ + return (lso_profile_t *)(uintptr_t)handle; +} + +int odp_lso_profile_destroy(odp_lso_profile_t lso_profile) +{ + lso_profile_t *lso_prof = lso_profile_ptr(lso_profile); + + if (lso_profile == ODP_LSO_PROFILE_INVALID || lso_prof->used == 0) { + ODP_ERR("Bad handle\n"); + return -1; + } + + odp_spinlock_lock(&pktio_global->lock); + lso_prof->used = 0; + pktio_global->num_lso_profiles--; + odp_spinlock_unlock(&pktio_global->lock); + + return 0; +} + +int odp_packet_lso_request(odp_packet_t pkt, const odp_packet_lso_opt_t *lso_opt) +{ + odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); + lso_profile_t *lso_prof = lso_profile_ptr(lso_opt->lso_profile); + uint32_t payload_offset = lso_opt->payload_offset; + + if (odp_unlikely(lso_opt->lso_profile == ODP_LSO_PROFILE_INVALID || lso_prof->used == 0)) { + ODP_ERR("Bad LSO profile handle\n"); + return -1; + } + + if (odp_unlikely(payload_offset > PKTIO_LSO_MAX_PAYLOAD_OFFSET)) { + ODP_ERR("Too large LSO payload offset\n"); + return -1; + } + + if (odp_unlikely((payload_offset + lso_opt->max_payload_len) > pkt_hdr->frame_len)) { + ODP_ERR("LSO options larger than packet data length\n"); + return -1; + } + + pkt_hdr->p.flags.lso = 1; + pkt_hdr->lso_max_payload = lso_opt->max_payload_len; + pkt_hdr->lso_profile_idx = lso_prof->index; + odp_packet_payload_offset_set(pkt, payload_offset); + + return 0; +} + +static int lso_update_custom(lso_profile_t *lso_prof, odp_packet_t pkt, int segnum) +{ + void *ptr; + int i, mod_op; + uint32_t offset; + uint8_t size; + int num_custom = lso_prof->param.custom.num_custom; + uint64_t u64 = 0; + uint32_t u32 = 0; + uint16_t u16 = 0; + uint8_t u8 = 0; + + for (i = 0; i < num_custom; i++) { + mod_op = lso_prof->param.custom.field[i].mod_op; + offset = lso_prof->param.custom.field[i].offset; + size = lso_prof->param.custom.field[i].size; + + if (size == 8) + ptr = &u64; + else if (size == 4) + ptr = &u32; + else if (size == 2) + ptr = &u16; + else + ptr = &u8; + + if (odp_packet_copy_to_mem(pkt, offset, size, ptr)) { + ODP_ERR("Read from packet failed at offset %u\n", offset); + return -1; + } + + if (mod_op == ODP_LSO_ADD_SEGMENT_NUM) { + if (size == 8) + u64 = odp_cpu_to_be_64(segnum + odp_be_to_cpu_64(u64)); + else if (size == 4) + u32 = odp_cpu_to_be_32(segnum + odp_be_to_cpu_32(u32)); + else if (size == 2) + u16 = odp_cpu_to_be_16(segnum + odp_be_to_cpu_16(u16)); + else + u8 += segnum; + } + + if (odp_packet_copy_from_mem(pkt, offset, size, ptr)) { + ODP_ERR("Write to packet failed at offset %u\n", offset); + return -1; + } + } + + return 0; +} + +static int pktout_send_lso(odp_pktout_queue_t queue, odp_packet_t packet, + const odp_packet_lso_opt_t *lso_opt) +{ + odp_pool_t pool; + odp_packet_t pkt; + int i, ret, num, num_pkt, num_full; + uint32_t hdr_len, pkt_len, pkt_payload, payload_len, left_over_len, offset; + int left_over = 0; + int num_free = 0; + int first_free = 0; + odp_lso_profile_t lso_profile = lso_opt->lso_profile; + lso_profile_t *lso_prof = lso_profile_ptr(lso_profile); + int num_custom = lso_prof->param.custom.num_custom; + + payload_len = lso_opt->max_payload_len; + hdr_len = lso_opt->payload_offset; + pkt_len = odp_packet_len(packet); + pkt_payload = pkt_len - hdr_len; + + if (odp_unlikely(hdr_len > PKTIO_LSO_MAX_PAYLOAD_OFFSET)) { + ODP_ERR("Too large LSO payload offset\n"); + return -1; + } + + if (odp_unlikely((hdr_len + payload_len) > pkt_len)) { + ODP_ERR("LSO options larger than packet data length\n"); + return -1; + } + + pool = odp_packet_pool(packet); + pkt_len = hdr_len + payload_len; + num_pkt = pkt_payload / payload_len; + num_full = num_pkt; + left_over_len = pkt_payload - (num_pkt * payload_len); + if (left_over_len) { + left_over = 1; + num_pkt++; + } + + /* Alloc packets */ + odp_packet_t pkt_out[num_pkt]; + + num = odp_packet_alloc_multi(pool, pkt_len, pkt_out, num_full); + if (odp_unlikely(num < num_full)) { + ODP_DBG("Alloc failed %i\n", num); + if (num > 0) { + num_free = num; + goto error; + } + } + + if (left_over) { + pkt = odp_packet_alloc(pool, hdr_len + left_over_len); + if (pkt == ODP_PACKET_INVALID) { + ODP_DBG("Alloc failed\n"); + num_free = num_full; + goto error; + } + + pkt_out[num_pkt - 1] = pkt; + } + + /* Copy headers */ + for (i = 0; i < num_pkt; i++) { + if (odp_packet_copy_from_pkt(pkt_out[i], 0, packet, 0, hdr_len)) { + ODP_ERR("Header copy failed\n"); + num_free = num_pkt; + goto error; + } + } + + /* Copy payload */ + for (i = 0; i < num_full; i++) { + offset = hdr_len + (i * payload_len); + if (odp_packet_copy_from_pkt(pkt_out[i], hdr_len, packet, offset, payload_len)) { + ODP_ERR("Payload copy failed\n"); + num_free = num_pkt; + goto error; + } + } + + if (left_over) { + offset = hdr_len + (num_full * payload_len); + if (odp_packet_copy_from_pkt(pkt_out[num_pkt - 1], hdr_len, packet, offset, + left_over_len)){ + ODP_ERR("Payload copy failed\n"); + num_free = num_pkt; + goto error; + } + } + + /* Update custom fields */ + for (i = 0; num_custom && i < num_pkt; i++) { + if (lso_update_custom(lso_prof, pkt_out[i], i)) { + ODP_ERR("Custom field update failed. Segment %i\n", i); + num_free = num_pkt; + goto error; + } + } + + ret = odp_pktout_send(queue, pkt_out, num_pkt); + + if (ret < num_pkt) { + ODP_DBG("Packet send failed %i\n", ret); + num_free = num_pkt; + if (ret > 0) { + first_free = ret; + num_free = num_pkt - ret; + } + } + + odp_packet_free(packet); + + return 0; + +error: + odp_packet_free_multi(&pkt_out[first_free], num_free); + return -1; +} + +int odp_pktout_send_lso(odp_pktout_queue_t queue, const odp_packet_t packet[], int num, + const odp_packet_lso_opt_t *opt) +{ + int i; + odp_packet_t pkt; + odp_packet_lso_opt_t lso_opt; + const odp_packet_lso_opt_t *opt_ptr = &lso_opt; + + if (odp_unlikely(num <= 0)) { + ODP_ERR("No packets\n"); + return -1; + } + + memset(&lso_opt, 0, sizeof(odp_packet_lso_opt_t)); + if (opt) + opt_ptr = opt; + + for (i = 0; i < num; i++) { + pkt = packet[i]; + + if (opt == NULL) { + odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); + + if (pkt_hdr->p.flags.lso == 0) { + ODP_ERR("No LSO options on packet %i\n", i); + if (i == 0) + return -1; + + return i; + } + + lso_opt.lso_profile = lso_profile_from_idx(pkt_hdr->lso_profile_idx); + lso_opt.payload_offset = odp_packet_payload_offset(pkt); + lso_opt.max_payload_len = pkt_hdr->lso_max_payload; + } + + if (odp_unlikely(pktout_send_lso(queue, pkt, opt_ptr))) { + ODP_DBG("LSO output failed on packet %i\n", i); + return i; + } + } + + return i; +} -- cgit v1.2.3 From d6594703406c3ff116060243ef6e0eb625d665b3 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Mon, 12 Oct 2020 11:41:41 +0300 Subject: validation: packet: add payload offset tests Added tests for the new payload offset metadata. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- test/validation/api/packet/packet.c | 121 ++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/test/validation/api/packet/packet.c b/test/validation/api/packet/packet.c index 87961f6d1..2054eb95f 100644 --- a/test/validation/api/packet/packet.c +++ b/test/validation/api/packet/packet.c @@ -827,6 +827,21 @@ static void packet_test_context(void) CU_ASSERT(odp_packet_user_ptr(pkt) == NULL); } +static void packet_test_payload_offset(void) +{ + odp_packet_t pkt = test_packet; + uint32_t pkt_len = odp_packet_len(pkt); + + CU_ASSERT(odp_packet_payload_offset_set(pkt, 42) == 0); + CU_ASSERT(odp_packet_payload_offset(pkt) == 42); + CU_ASSERT(odp_packet_payload_offset_set(pkt, 0) == 0); + CU_ASSERT(odp_packet_payload_offset(pkt) == 0); + CU_ASSERT(odp_packet_payload_offset_set(pkt, pkt_len - 1) == 0); + CU_ASSERT(odp_packet_payload_offset(pkt) == pkt_len - 1); + CU_ASSERT(odp_packet_payload_offset_set(pkt, ODP_PACKET_OFFSET_INVALID) == 0); + CU_ASSERT(odp_packet_payload_offset(pkt) == ODP_PACKET_OFFSET_INVALID); +} + static void packet_test_layer_offsets(void) { odp_packet_t pkt = test_packet; @@ -1412,6 +1427,110 @@ static void _packet_compare_offset(odp_packet_t pkt1, uint32_t off1, } } +static void packet_test_meta_data_copy(void) +{ + odp_packet_t pkt, copy; + odp_pool_param_t pool_param; + odp_pool_t pool; + odp_pktio_t pktio; + odp_time_t t1, t2; + + memcpy(&pool_param, &default_param, sizeof(odp_pool_param_t)); + pool = odp_pool_create("meta_data_copy", &pool_param); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + pktio = odp_pktio_open("loop", pool, NULL); + CU_ASSERT_FATAL(pktio != ODP_PKTIO_INVALID); + + t1 = odp_time_global(); + + pkt = odp_packet_alloc(pool, packet_len); + CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID); + CU_ASSERT(odp_packet_has_l2(pkt) == 0); + CU_ASSERT(odp_packet_has_l3(pkt) == 0); + CU_ASSERT(odp_packet_has_l4(pkt) == 0); + CU_ASSERT(odp_packet_has_eth(pkt) == 0); + CU_ASSERT(odp_packet_has_eth_bcast(pkt) == 0); + CU_ASSERT(odp_packet_has_eth_mcast(pkt) == 0); + CU_ASSERT(odp_packet_has_jumbo(pkt) == 0); + CU_ASSERT(odp_packet_has_vlan(pkt) == 0); + CU_ASSERT(odp_packet_has_vlan_qinq(pkt) == 0); + CU_ASSERT(odp_packet_has_arp(pkt) == 0); + CU_ASSERT(odp_packet_has_ipv4(pkt) == 0); + CU_ASSERT(odp_packet_has_ipv6(pkt) == 0); + CU_ASSERT(odp_packet_has_ip_bcast(pkt) == 0); + CU_ASSERT(odp_packet_has_ip_mcast(pkt) == 0); + CU_ASSERT(odp_packet_has_ipfrag(pkt) == 0); + CU_ASSERT(odp_packet_has_ipopt(pkt) == 0); + CU_ASSERT(odp_packet_has_ipsec(pkt) == 0); + CU_ASSERT(odp_packet_has_udp(pkt) == 0); + CU_ASSERT(odp_packet_has_tcp(pkt) == 0); + CU_ASSERT(odp_packet_has_sctp(pkt) == 0); + CU_ASSERT(odp_packet_has_icmp(pkt) == 0); + CU_ASSERT(odp_packet_input(pkt) == ODP_PKTIO_INVALID); + CU_ASSERT(odp_packet_l3_offset(pkt) == ODP_PACKET_OFFSET_INVALID); + CU_ASSERT(odp_packet_l4_offset(pkt) == ODP_PACKET_OFFSET_INVALID); + CU_ASSERT(odp_packet_payload_offset(pkt) == ODP_PACKET_OFFSET_INVALID); + + odp_packet_has_l2_set(pkt, 1); + odp_packet_has_l3_set(pkt, 1); + odp_packet_has_l4_set(pkt, 1); + odp_packet_has_eth_set(pkt, 1); + odp_packet_has_eth_bcast_set(pkt, 1); + odp_packet_has_eth_mcast_set(pkt, 1); + odp_packet_has_jumbo_set(pkt, 1); + odp_packet_has_vlan_set(pkt, 1); + odp_packet_has_vlan_qinq_set(pkt, 1); + odp_packet_has_arp_set(pkt, 1); + odp_packet_has_ipv4_set(pkt, 1); + odp_packet_has_ipv6_set(pkt, 1); + odp_packet_has_ip_bcast_set(pkt, 1); + odp_packet_has_ip_mcast_set(pkt, 1); + odp_packet_has_ipfrag_set(pkt, 1); + odp_packet_has_ipopt_set(pkt, 1); + odp_packet_has_ipsec_set(pkt, 1); + odp_packet_has_udp_set(pkt, 1); + odp_packet_has_tcp_set(pkt, 1); + odp_packet_has_sctp_set(pkt, 1); + odp_packet_has_icmp_set(pkt, 1); + + odp_packet_input_set(pkt, pktio); + odp_packet_user_ptr_set(pkt, (void *)(uintptr_t)0xdeadbeef); + CU_ASSERT(odp_packet_l2_offset_set(pkt, 20) == 0); + CU_ASSERT(odp_packet_l3_offset_set(pkt, 30) == 0); + CU_ASSERT(odp_packet_l4_offset_set(pkt, 40) == 0); + CU_ASSERT(odp_packet_payload_offset_set(pkt, 50) == 0); + odp_packet_flow_hash_set(pkt, 0xcafe); + odp_packet_ts_set(pkt, t1); + odp_packet_color_set(pkt, ODP_PACKET_RED); + odp_packet_drop_eligible_set(pkt, 1); + odp_packet_shaper_len_adjust_set(pkt, 1); + + /* Make a copy of the packet and check that meta data values are the same */ + copy = odp_packet_copy(pkt, pool); + CU_ASSERT_FATAL(copy != ODP_PACKET_INVALID); + + _packet_compare_inflags(pkt, copy); + CU_ASSERT(odp_packet_input(copy) == pktio); + CU_ASSERT(odp_packet_user_ptr(copy) == (void *)(uintptr_t)0xdeadbeef); + CU_ASSERT(odp_packet_l2_offset(copy) == 20); + CU_ASSERT(odp_packet_l3_offset(copy) == 30); + CU_ASSERT(odp_packet_l4_offset(copy) == 40); + CU_ASSERT(odp_packet_payload_offset(copy) == 50); + CU_ASSERT(odp_packet_flow_hash(copy) == 0xcafe); + t2 = odp_packet_ts(copy); + CU_ASSERT(odp_time_cmp(t2, t1) == 0); + CU_ASSERT(odp_packet_color(copy) == ODP_PACKET_RED); + CU_ASSERT(odp_packet_drop_eligible(copy) == 1); + CU_ASSERT(odp_packet_shaper_len_adjust(copy) == 1); + + odp_packet_free(pkt); + odp_packet_free(copy); + + CU_ASSERT(odp_pktio_close(pktio) == 0); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + static void packet_test_copy(void) { odp_packet_t pkt; @@ -3981,12 +4100,14 @@ odp_testinfo_t packet_suite[] = { ODP_TEST_INFO(packet_test_headroom), ODP_TEST_INFO(packet_test_tailroom), ODP_TEST_INFO(packet_test_context), + ODP_TEST_INFO(packet_test_payload_offset), ODP_TEST_INFO(packet_test_event_conversion), ODP_TEST_INFO(packet_test_layer_offsets), ODP_TEST_INFO(packet_test_segment_last), ODP_TEST_INFO(packet_test_in_flags), ODP_TEST_INFO(packet_test_error_flags), ODP_TEST_INFO(packet_test_add_rem_data), + ODP_TEST_INFO(packet_test_meta_data_copy), ODP_TEST_INFO(packet_test_copy), ODP_TEST_INFO(packet_test_copydata), ODP_TEST_INFO(packet_test_concatsplit), -- cgit v1.2.3 From 38c3ac153583fa2c7b5e88b9f12161f1b5c730b3 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Wed, 23 Sep 2020 13:04:16 +0300 Subject: validation: pktio: add LSO test suite Added LSO tests as a new test suite under pktio tests. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- test/common/test_packet_parser.h | 102 +++++ test/validation/api/pktio/Makefile.am | 2 +- test/validation/api/pktio/lso.c | 677 ++++++++++++++++++++++++++++++++++ test/validation/api/pktio/lso.h | 19 + test/validation/api/pktio/pktio.c | 2 + 5 files changed, 801 insertions(+), 1 deletion(-) create mode 100644 test/validation/api/pktio/lso.c create mode 100644 test/validation/api/pktio/lso.h diff --git a/test/common/test_packet_parser.h b/test/common/test_packet_parser.h index 745a620c3..22e60de23 100644 --- a/test/common/test_packet_parser.h +++ b/test/common/test_packet_parser.h @@ -15,6 +15,108 @@ extern "C" { /* Test packets without CRC */ +/* Ethernet type 0x88B5: EthernetIEEE Std 802 - Local Experimental Ethertype 1 + * + * Imaginary, custom protocol on top of Ethernet. + */ +static const uint8_t test_packet_custom_eth_1[] = { + /* Ethernet */ + 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x04, 0x00, 0x88, 0xB5, + /* Header fields (16 bit): + * packet length, segment number, segment offset, port number */ + 0x00, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, + /* Payload 701 bytes */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, + 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, + 0x00, 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, + 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, + 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, + 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, + 0x00, 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, + 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, + 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, + 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, + 0x00, 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, + 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, + 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, + 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, + 0x00, 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, + 0x00, 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, + 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, + 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, + 0x00, 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, + 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, + 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, + 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, + 0x00, 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, + 0x00, 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, + 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, + 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, 0x00, 0x67, + 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, + 0x00, 0x6C, 0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, + 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, + 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x77, + 0x00, 0x78, 0x00, 0x79, 0x00, 0x7A, 0x00, 0x7B, + 0x00, 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, + 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, + 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, + 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, + 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, + 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, + 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, + 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, + 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, + 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, + 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00, + 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, + 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00, + 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, + 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, + 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, + 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00, + 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, + 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, + 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, + 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, + 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, + 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00, + 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, + 0xDC, 0x00, 0xDD, 0x00, 0xDE +}; + /* ARP request */ static const uint8_t test_packet_arp[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, diff --git a/test/validation/api/pktio/Makefile.am b/test/validation/api/pktio/Makefile.am index ffd1827be..c63809f8c 100644 --- a/test/validation/api/pktio/Makefile.am +++ b/test/validation/api/pktio/Makefile.am @@ -1,4 +1,4 @@ include ../Makefile.inc test_PROGRAMS = pktio_main -pktio_main_SOURCES = pktio.c parser.c parser.h +pktio_main_SOURCES = pktio.c parser.c parser.h lso.c lso.h diff --git a/test/validation/api/pktio/lso.c b/test/validation/api/pktio/lso.c new file mode 100644 index 000000000..4020d1db5 --- /dev/null +++ b/test/validation/api/pktio/lso.c @@ -0,0 +1,677 @@ +/* Copyright (c) 2020, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include + +#include "lso.h" + +#define MAX_NUM_IFACES 2 +#define PKT_POOL_NUM 256 +#define PKT_POOL_LEN (2 * 1024) + +/* Maximum number of segments test is prepared to receive per outgoing packet */ +#define MAX_NUM_SEG 256 + +/* Max payload bytes per LSO segment */ +#define CUSTOM_MAX_PAYLOAD 288 + +/* Pktio interface info + */ +typedef struct { + const char *name; + odp_pktio_t hdl; + odp_pktout_queue_t pktout; + odp_pktin_queue_t pktin; + odp_pktio_capability_t capa; +} pktio_info_t; + +/* Interface names used for testing */ +static const char *iface_name[MAX_NUM_IFACES]; + +/* Test interfaces */ +static pktio_info_t pktios[MAX_NUM_IFACES]; +static pktio_info_t *pktio_a; +static pktio_info_t *pktio_b; + +/* Number of interfaces being used (1=loopback, 2=pair) */ +static int num_ifaces; + +/* Some interface types cannot be restarted. + * These control test case execution in that case. */ +static int num_starts; +static int disable_restart; + +/* While testing real-world interfaces additional time may be needed for + * external network to enable link to pktio interface that just become up. */ +static int wait_for_network; + +/* LSO test packet pool */ +odp_pool_t lso_pool = ODP_POOL_INVALID; + +static inline void wait_linkup(odp_pktio_t pktio) +{ + /* wait 1 second for link up */ + uint64_t wait_ns = (10 * ODP_TIME_MSEC_IN_NS); + int wait_num = 100; + int i; + int ret = -1; + + for (i = 0; i < wait_num; i++) { + ret = odp_pktio_link_status(pktio); + if (ret == ODP_PKTIO_LINK_STATUS_UNKNOWN || ret == ODP_PKTIO_LINK_STATUS_UP) + break; + /* link is down, call status again after delay */ + odp_time_wait_ns(wait_ns); + } +} + +static int pkt_pool_create(void) +{ + odp_pool_capability_t capa; + odp_pool_param_t params; + + if (odp_pool_capability(&capa) != 0) { + ODPH_ERR("Pool capability failed\n"); + return -1; + } + + if (capa.pkt.max_num && capa.pkt.max_num < PKT_POOL_NUM) { + ODPH_ERR("Packet pool size not supported. Max %" PRIu32 "\n", capa.pkt.max_num); + return -1; + } else if (capa.pkt.max_len && capa.pkt.max_len < PKT_POOL_LEN) { + ODPH_ERR("Packet length not supported.\n"); + return -1; + } else if (capa.pkt.max_seg_len && + capa.pkt.max_seg_len < PKT_POOL_LEN) { + ODPH_ERR("Segment length not supported.\n"); + return -1; + } + + odp_pool_param_init(¶ms); + params.pkt.seg_len = PKT_POOL_LEN; + params.pkt.len = PKT_POOL_LEN; + params.pkt.num = PKT_POOL_NUM; + params.type = ODP_POOL_PACKET; + + lso_pool = odp_pool_create("lso_pool", ¶ms); + if (lso_pool == ODP_POOL_INVALID) { + ODPH_ERR("Packet pool create failed.\n"); + return -1; + } + + return 0; +} + +static odp_pktio_t create_pktio(int idx, const char *name, odp_pool_t pool) +{ + odp_pktio_t pktio; + odp_pktio_config_t config; + odp_pktio_param_t pktio_param; + odp_pktio_capability_t *capa; + int tx = (idx == 0) ? 1 : 0; + int rx = (idx == 0) ? 0 : 1; + + if (num_ifaces == 1) { + tx = 1; + rx = 1; + } + + odp_pktio_param_init(&pktio_param); + pktio_param.in_mode = ODP_PKTIN_MODE_DIRECT; + pktio_param.out_mode = ODP_PKTOUT_MODE_DIRECT; + + pktio = odp_pktio_open(name, pool, &pktio_param); + pktios[idx].hdl = pktio; + pktios[idx].name = name; + if (pktio == ODP_PKTIO_INVALID) { + ODPH_ERR("Failed to open %s\n", name); + return ODP_PKTIO_INVALID; + } + + if (odp_pktio_capability(pktio, &pktios[idx].capa)) { + ODPH_ERR("Pktio capa failed: %s\n", name); + return ODP_PKTIO_INVALID; + } + + capa = &pktios[idx].capa; + + odp_pktio_config_init(&config); + + if (tx) { + if (capa->config.enable_lso) + config.enable_lso = 1; + else + ODPH_DBG("LSO not supported\n"); + } + + if (rx) { + config.parser.layer = ODP_PROTO_LAYER_ALL; + if (capa->config.pktin.bit.ipv4_chksum) + config.pktin.bit.ipv4_chksum = 1; + else + ODPH_DBG("IPv4 checksum not verified\n"); + } + + if (odp_pktio_config(pktio, &config)) { + ODPH_ERR("Failed to configure %s\n", name); + return ODP_PKTIO_INVALID; + } + + /* By default, single input and output queue is used */ + if (odp_pktin_queue_config(pktio, NULL)) { + ODPH_ERR("Failed to config input queue for %s\n", name); + return ODP_PKTIO_INVALID; + } + if (odp_pktout_queue_config(pktio, NULL)) { + ODPH_ERR("Failed to config output queue for %s\n", name); + return ODP_PKTIO_INVALID; + } + + if (wait_for_network) + odp_time_wait_ns(ODP_TIME_SEC_IN_NS / 4); + + return pktio; +} + +static odp_packet_t create_packet(const uint8_t *data, uint32_t len) +{ + odp_packet_t pkt; + + pkt = odp_packet_alloc(lso_pool, len); + if (pkt == ODP_PACKET_INVALID) + return ODP_PACKET_INVALID; + + if (odp_packet_copy_from_mem(pkt, 0, len, data)) { + ODPH_ERR("Failed to copy test packet data\n"); + odp_packet_free(pkt); + return ODP_PACKET_INVALID; + } + + odp_packet_l2_offset_set(pkt, 0); + + return pkt; +} + +static void pktio_pkt_set_macs(odp_packet_t pkt, odp_pktio_t src, odp_pktio_t dst) +{ + uint32_t len; + odph_ethhdr_t *eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, &len); + int ret; + + ret = odp_pktio_mac_addr(src, ð->src, ODP_PKTIO_MACADDR_MAXSIZE); + CU_ASSERT(ret == ODPH_ETHADDR_LEN); + CU_ASSERT(ret <= ODP_PKTIO_MACADDR_MAXSIZE); + + ret = odp_pktio_mac_addr(dst, ð->dst, ODP_PKTIO_MACADDR_MAXSIZE); + CU_ASSERT(ret == ODPH_ETHADDR_LEN); + CU_ASSERT(ret <= ODP_PKTIO_MACADDR_MAXSIZE); +} + +static int send_packets(odp_lso_profile_t lso_profile, pktio_info_t *pktio_a, pktio_info_t *pktio_b, + const uint8_t *data, uint32_t len, uint32_t hdr_len, uint32_t max_payload, + uint32_t l3_offset, int use_opt) +{ + odp_packet_t pkt; + int ret; + odp_packet_lso_opt_t lso_opt; + odp_packet_lso_opt_t *opt_ptr = NULL; + int retries = 10; + + pkt = create_packet(data, len); + if (pkt == ODP_PACKET_INVALID) { + CU_FAIL("failed to generate test packet"); + return -1; + } + + pktio_pkt_set_macs(pkt, pktio_a->hdl, pktio_b->hdl); + CU_ASSERT(odp_packet_has_lso_request(pkt) == 0); + + memset(&lso_opt, 0, sizeof(odp_packet_lso_opt_t)); + lso_opt.lso_profile = lso_profile; + lso_opt.payload_offset = hdr_len; + lso_opt.max_payload_len = max_payload; + + if (use_opt) { + opt_ptr = &lso_opt; + } else { + if (odp_packet_lso_request(pkt, &lso_opt)) { + CU_FAIL("LSO request failed"); + return -1; + } + + CU_ASSERT(odp_packet_has_lso_request(pkt)); + CU_ASSERT(odp_packet_payload_offset(pkt) == hdr_len); + } + + if (l3_offset) + odp_packet_l3_offset_set(pkt, l3_offset); + + while (retries) { + ret = odp_pktout_send_lso(pktio_a->pktout, &pkt, 1, opt_ptr); + + CU_ASSERT_FATAL(ret < 2); + + if (ret < 0) { + CU_FAIL("LSO send failed\n"); + odp_packet_free(pkt); + return -1; + } + if (ret == 1) + break; + + odp_time_wait_ns(10 * ODP_TIME_MSEC_IN_NS); + retries--; + } + + if (ret < 1) { + CU_FAIL("LSO send timeout\n"); + odp_packet_free(pkt); + return -1; + } + + return 0; +} + +static int recv_packets(pktio_info_t *pktio_info, uint64_t timeout_ns, + odp_packet_t *pkt_out, int max_num) +{ + odp_packet_t pkt; + odp_time_t wait_time, end; + int ret; + odp_pktin_queue_t pktin = pktio_info->pktin; + int num = 0; + + wait_time = odp_time_local_from_ns(timeout_ns); + end = odp_time_sum(odp_time_local(), wait_time); + + do { + pkt = ODP_PACKET_INVALID; + ret = odp_pktin_recv(pktin, &pkt, 1); + + CU_ASSERT_FATAL(ret < 2); + if (ret < 0) { + CU_FAIL("Packet receive failed\n"); + if (num) + odp_packet_free_multi(pkt_out, num); + return -1; + } + + if (ret == 1) { + CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID); + pkt_out[num] = pkt; + num++; + if (num == max_num) { + CU_FAIL("Too many packets received\n"); + return num; + } + } + } while (odp_time_cmp(end, odp_time_local()) > 0); + + return num; +} + +static int compare_data(odp_packet_t pkt, uint32_t offset, const uint8_t *data, uint32_t len) +{ + uint32_t i; + uint8_t *u8; + + for (i = 0; i < len; i++) { + u8 = odp_packet_offset(pkt, offset + i, NULL, NULL); + if (*u8 != data[i]) + return i; + } + + return -1; +} + +static int start_interfaces(void) +{ + int i; + + for (i = 0; i < num_ifaces; ++i) { + odp_pktio_t pktio = pktios[i].hdl; + + if (odp_pktio_start(pktio)) { + ODPH_ERR("Failed to start interface: %s\n", pktios[i].name); + return -1; + } + + wait_linkup(pktio); + } + + return 0; +} + +static int stop_interfaces(void) +{ + int i; + + for (i = 0; i < num_ifaces; ++i) { + odp_pktio_t pktio = pktios[i].hdl; + + if (odp_pktio_stop(pktio)) { + ODPH_ERR("Failed to stop interface: %s\n", pktios[i].name); + return -1; + } + } + + return 0; +} + +int lso_suite_init(void) +{ + int i; + + if (getenv("ODP_PKTIO_TEST_DISABLE_START_STOP")) + disable_restart = 1; + + if (getenv("ODP_WAIT_FOR_NETWORK")) + wait_for_network = 1; + + iface_name[0] = getenv("ODP_PKTIO_IF0"); + iface_name[1] = getenv("ODP_PKTIO_IF1"); + num_ifaces = 1; + + if (!iface_name[0]) { + printf("No interfaces specified, using default \"loop\".\n"); + iface_name[0] = "loop"; + } else if (!iface_name[1]) { + printf("Using loopback interface: %s\n", iface_name[0]); + } else { + num_ifaces = 2; + printf("Using paired interfaces: %s %s\n", + iface_name[0], iface_name[1]); + } + + if (pkt_pool_create() != 0) { + ODPH_ERR("Failed to create pool\n"); + return -1; + } + + /* Create pktios and associate input/output queues */ + for (i = 0; i < num_ifaces; ++i) { + odp_pktio_t pktio; + const char *name = iface_name[i]; + + pktio = create_pktio(i, name, lso_pool); + + if (pktio == ODP_PKTIO_INVALID) { + ODPH_ERR("Failed to open interface: %s\n", name); + return -1; + } + + if (odp_pktout_queue(pktio, &pktios[i].pktout, 1) != 1) { + ODPH_ERR("Failed to get pktout queue: %s\n", name); + return -1; + } + + if (odp_pktin_queue(pktio, &pktios[i].pktin, 1) != 1) { + ODPH_ERR("Failed to get pktin queue: %s\n", name); + return -1; + } + } + + pktio_a = &pktios[0]; + pktio_b = &pktios[1]; + if (num_ifaces == 1) + pktio_b = pktio_a; + + return 0; +} + +int lso_suite_term(void) +{ + int i; + int ret = 0; + + for (i = 0; i < num_ifaces; ++i) { + if (odp_pktio_close(pktios[i].hdl)) { + ODPH_ERR("Failed to close pktio: %s\n", pktios[i].name); + ret = -1; + } + } + + if (odp_pool_destroy(lso_pool) != 0) { + ODPH_ERR("Failed to destroy pool\n"); + ret = -1; + } + + if (odp_cunit_print_inactive()) + ret = -1; + + return ret; +} + +static int check_lso_custom(void) +{ + if (pktio_a->capa.lso.max_profiles == 0 || pktio_a->capa.lso.max_profiles_per_pktio == 0) + return ODP_TEST_INACTIVE; + + if (pktio_a->capa.lso.proto.custom == 0 || pktio_a->capa.lso.mod_op.add_segment_num == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int check_lso_custom_restart(void) +{ + if (check_lso_custom() == ODP_TEST_INACTIVE) + return ODP_TEST_INACTIVE; + + if (disable_restart && num_starts > 0) + return ODP_TEST_INACTIVE; + + /* Run only one packet IO test case when interface restart is disabled */ + num_starts++; + + return ODP_TEST_ACTIVE; +} + +static void lso_capability(void) +{ + /* LSO not supported when max_profiles is zero */ + if (pktio_a->capa.lso.max_profiles == 0 || pktio_a->capa.lso.max_profiles_per_pktio == 0) + return; + + CU_ASSERT(pktio_a->capa.lso.max_profiles >= pktio_a->capa.lso.max_profiles_per_pktio); + CU_ASSERT(pktio_a->capa.lso.max_packet_segments > 0); + /* At least 32 bytes of payload */ + CU_ASSERT(pktio_a->capa.lso.max_payload_len >= 32); + /* LSO can create at least two segments */ + CU_ASSERT(pktio_a->capa.lso.max_segments > 1); + /* LSO can copy at least Ethernet header to segments */ + CU_ASSERT(pktio_a->capa.lso.max_payload_offset >= 14); + + if (pktio_a->capa.lso.proto.custom) { + CU_ASSERT(pktio_a->capa.lso.max_num_custom > 0); + + CU_ASSERT(pktio_a->capa.lso.mod_op.add_segment_num || + pktio_a->capa.lso.mod_op.add_payload_len || + pktio_a->capa.lso.mod_op.add_payload_offset) + } +} + +static void lso_create_custom_profile(void) +{ + odp_lso_profile_param_t param_0, param_1; + odp_lso_profile_t profile_0, profile_1; + + odp_lso_profile_param_init(¶m_0); + CU_ASSERT(param_0.lso_proto == ODP_LSO_PROTO_NONE); + CU_ASSERT(param_0.custom.num_custom == 0); + + param_0.lso_proto = ODP_LSO_PROTO_CUSTOM; + param_0.custom.num_custom = 1; + param_0.custom.field[0].mod_op = ODP_LSO_ADD_SEGMENT_NUM; + param_0.custom.field[0].offset = 16; + param_0.custom.field[0].size = 2; + + profile_0 = odp_lso_profile_create(pktio_a->hdl, ¶m_0); + CU_ASSERT_FATAL(profile_0 != ODP_LSO_PROFILE_INVALID); + + CU_ASSERT_FATAL(odp_lso_profile_destroy(profile_0) == 0); + + if (pktio_a->capa.lso.max_profiles < 2 || pktio_a->capa.lso.max_num_custom < 3) + return; + + if (pktio_a->capa.lso.mod_op.add_payload_len == 0 || + pktio_a->capa.lso.mod_op.add_payload_offset == 0) + return; + + odp_lso_profile_param_init(¶m_1); + param_1.lso_proto = ODP_LSO_PROTO_CUSTOM; + param_1.custom.num_custom = 3; + param_1.custom.field[0].mod_op = ODP_LSO_ADD_PAYLOAD_LEN; + param_1.custom.field[0].offset = 14; + param_1.custom.field[0].size = 2; + param_1.custom.field[1].mod_op = ODP_LSO_ADD_SEGMENT_NUM; + param_1.custom.field[1].offset = 16; + param_1.custom.field[1].size = 2; + param_1.custom.field[2].mod_op = ODP_LSO_ADD_PAYLOAD_OFFSET; + param_1.custom.field[2].offset = 18; + param_1.custom.field[2].size = 2; + + profile_0 = odp_lso_profile_create(pktio_a->hdl, ¶m_0); + CU_ASSERT_FATAL(profile_0 != ODP_LSO_PROFILE_INVALID); + + profile_1 = odp_lso_profile_create(pktio_a->hdl, ¶m_1); + CU_ASSERT_FATAL(profile_1 != ODP_LSO_PROFILE_INVALID); + + CU_ASSERT_FATAL(odp_lso_profile_destroy(profile_1) == 0); + CU_ASSERT_FATAL(odp_lso_profile_destroy(profile_0) == 0); +} + +static void test_lso_request_clear(odp_lso_profile_t lso_profile, const uint8_t *data, + uint32_t len, uint32_t hdr_len, uint32_t max_payload) +{ + odp_packet_t pkt; + odp_packet_lso_opt_t lso_opt; + + memset(&lso_opt, 0, sizeof(odp_packet_lso_opt_t)); + lso_opt.lso_profile = lso_profile; + lso_opt.payload_offset = hdr_len; + lso_opt.max_payload_len = max_payload; + + pkt = create_packet(data, len); + CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID); + CU_ASSERT(odp_packet_has_lso_request(pkt) == 0); + CU_ASSERT(odp_packet_lso_request(pkt, &lso_opt) == 0); + CU_ASSERT(odp_packet_has_lso_request(pkt) != 0); + CU_ASSERT(odp_packet_payload_offset(pkt) == hdr_len); + odp_packet_lso_request_clr(pkt); + CU_ASSERT(odp_packet_has_lso_request(pkt) == 0); + CU_ASSERT(odp_packet_payload_offset(pkt) == hdr_len); + CU_ASSERT(odp_packet_payload_offset_set(pkt, ODP_PACKET_OFFSET_INVALID) == 0); + CU_ASSERT(odp_packet_payload_offset(pkt) == ODP_PACKET_OFFSET_INVALID); + + odp_packet_free(pkt); +} + +static void lso_send_custom_eth(int use_opt) +{ + int i, ret, num; + odp_lso_profile_param_t param; + odp_lso_profile_t profile; + uint32_t offset, len, payload_len, payload_sum; + uint16_t segnum; + odp_packet_t pkt_out[MAX_NUM_SEG]; + /* Ethernet 14B + custom headers 8B */ + uint32_t hdr_len = 22; + /* Offset to "segment number" field */ + uint32_t segnum_offset = 16; + uint32_t pkt_len = sizeof(test_packet_custom_eth_1); + uint32_t sent_payload = pkt_len - hdr_len; + uint32_t max_payload = CUSTOM_MAX_PAYLOAD; + + odp_lso_profile_param_init(¶m); + param.lso_proto = ODP_LSO_PROTO_CUSTOM; + param.custom.num_custom = 1; + param.custom.field[0].mod_op = ODP_LSO_ADD_SEGMENT_NUM; + param.custom.field[0].offset = segnum_offset; + param.custom.field[0].size = 2; + + profile = odp_lso_profile_create(pktio_a->hdl, ¶m); + CU_ASSERT_FATAL(profile != ODP_LSO_PROFILE_INVALID); + + CU_ASSERT_FATAL(start_interfaces() == 0); + + test_lso_request_clear(profile, test_packet_custom_eth_1, pkt_len, hdr_len, max_payload); + + ret = send_packets(profile, pktio_a, pktio_b, test_packet_custom_eth_1, + pkt_len, hdr_len, max_payload, 0, use_opt); + CU_ASSERT_FATAL(ret == 0); + + ODPH_DBG("\n Sent payload length: %u bytes\n", sent_payload); + + /* Wait 1 sec to receive all created segments. Timeout and MAX_NUM_SEG values should be + * large enough to ensure that we receive all created segments. */ + num = recv_packets(pktio_b, ODP_TIME_SEC_IN_NS, pkt_out, MAX_NUM_SEG); + CU_ASSERT(num > 0); + CU_ASSERT(num < MAX_NUM_SEG); + + offset = hdr_len; + payload_sum = 0; + segnum = 0xffff; + for (i = 0; i < num; i++) { + len = odp_packet_len(pkt_out[i]); + payload_len = len - hdr_len; + + ret = odp_packet_copy_to_mem(pkt_out[i], segnum_offset, 2, &segnum); + + if (ret == 0) { + segnum = odp_be_to_cpu_16(segnum); + CU_ASSERT(segnum == i); + } else { + CU_FAIL("Seg num field read failed\n"); + } + + ODPH_DBG(" LSO segment[%u] payload: %u bytes\n", segnum, payload_len); + + CU_ASSERT(payload_len <= CUSTOM_MAX_PAYLOAD); + + if (compare_data(pkt_out[i], hdr_len, + test_packet_custom_eth_1 + offset, payload_len) >= 0) { + ODPH_ERR(" Payload compare failed at offset %u\n", offset); + CU_FAIL("Payload compare failed\n"); + } + + offset += payload_len; + payload_sum += payload_len; + } + + ODPH_DBG(" Received payload length: %u bytes\n", payload_sum); + + CU_ASSERT(payload_sum == sent_payload); + + if (num > 0) + odp_packet_free_multi(pkt_out, num); + + CU_ASSERT_FATAL(stop_interfaces() == 0); + + CU_ASSERT_FATAL(odp_lso_profile_destroy(profile) == 0); +} + +static void lso_send_custom_eth_use_pkt_meta(void) +{ + lso_send_custom_eth(0); +} + +static void lso_send_custom_eth_use_opt(void) +{ + lso_send_custom_eth(1); +} + +odp_testinfo_t lso_suite[] = { + ODP_TEST_INFO(lso_capability), + ODP_TEST_INFO_CONDITIONAL(lso_create_custom_profile, check_lso_custom), + ODP_TEST_INFO_CONDITIONAL(lso_send_custom_eth_use_pkt_meta, check_lso_custom_restart), + ODP_TEST_INFO_CONDITIONAL(lso_send_custom_eth_use_opt, check_lso_custom_restart), + ODP_TEST_INFO_NULL +}; diff --git a/test/validation/api/pktio/lso.h b/test/validation/api/pktio/lso.h new file mode 100644 index 000000000..ce3dc7b64 --- /dev/null +++ b/test/validation/api/pktio/lso.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2020, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ODP_TEST_PKTIO_LSO_H_ +#define _ODP_TEST_PKTIO_LSO_H_ + +#include + +/* test array init/term functions: */ +int lso_suite_term(void); +int lso_suite_init(void); + +/* test arrays: */ +extern odp_testinfo_t lso_suite[]; + +#endif diff --git a/test/validation/api/pktio/pktio.c b/test/validation/api/pktio/pktio.c index 87d5b6ad4..92c3f4ab0 100644 --- a/test/validation/api/pktio/pktio.c +++ b/test/validation/api/pktio/pktio.c @@ -13,6 +13,7 @@ #include #include "parser.h" +#include "lso.h" #define PKT_BUF_NUM 128 #define PKT_BUF_SIZE (9 * 1024) @@ -3481,6 +3482,7 @@ odp_suiteinfo_t pktio_suites[] = { pktio_suite_term, pktio_suite_segmented}, {"Packet parser", parser_suite_init, parser_suite_term, parser_suite}, {"Packet vector", pktv_suite_init, pktv_suite_term, pktv_suite}, + {"Large Segment Offload", lso_suite_init, lso_suite_term, lso_suite}, ODP_SUITE_INFO_NULL }; -- cgit v1.2.3 From 81eef4e66a3b2f19f2ac8e81819474c7cf79e3c7 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Wed, 30 Dec 2020 15:52:37 +0200 Subject: linux-gen: pktio: add LSO support for IPv4 fragmentation Add support for IPv4 fragmentation (ODP_LSO_PROTO_IPV4) to LSO implementation. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- platform/linux-generic/include/protocols/ip.h | 4 +- platform/linux-generic/odp_packet_io.c | 122 ++++++++++++++++++++------ 2 files changed, 97 insertions(+), 29 deletions(-) diff --git a/platform/linux-generic/include/protocols/ip.h b/platform/linux-generic/include/protocols/ip.h index 19aef3dcc..d13c7c9b0 100644 --- a/platform/linux-generic/include/protocols/ip.h +++ b/platform/linux-generic/include/protocols/ip.h @@ -62,8 +62,8 @@ extern "C" { /** @internal Returns IPv4 Don't fragment */ #define _ODP_IPV4HDR_FLAGS_DONT_FRAG(frag_offset) ((frag_offset) & 0x4000) -/** @internal Returns IPv4 more fragments */ -#define _ODP_IPV4HDR_FLAGS_MORE_FRAGS(frag_offset) ((frag_offset) & 0x2000) +/* IPv4 more fragments flag in the frag_offset field */ +#define _ODP_IPV4HDR_FRAG_OFFSET_MORE_FRAGS 0x2000 /** @internal Returns IPv4 fragment offset */ #define _ODP_IPV4HDR_FRAG_OFFSET(frag_offset) ((frag_offset) & 0x1fff) diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index 88e6c0dcf..23c92931d 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -1750,6 +1750,7 @@ int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa) capa->lso.max_payload_len = mtu - PKTIO_LSO_MAX_PAYLOAD_OFFSET; capa->lso.max_payload_offset = PKTIO_LSO_MAX_PAYLOAD_OFFSET; capa->lso.max_num_custom = ODP_LSO_MAX_CUSTOM; + capa->lso.proto.ipv4 = 1; capa->lso.proto.custom = 1; capa->lso.mod_op.add_segment_num = 1; } @@ -2504,37 +2505,40 @@ odp_lso_profile_t odp_lso_profile_create(odp_pktio_t pktio, const odp_lso_profil lso_profile_t *lso_prof = NULL; (void)pktio; - /* Currently only custom implemented */ - if (param->lso_proto != ODP_LSO_PROTO_CUSTOM) { + /* Currently only IPv4 and custom implemented */ + if (param->lso_proto != ODP_LSO_PROTO_IPV4 && + param->lso_proto != ODP_LSO_PROTO_CUSTOM) { ODP_ERR("Protocol not supported\n"); return ODP_LSO_PROFILE_INVALID; } - num_custom = param->custom.num_custom; - if (num_custom > ODP_LSO_MAX_CUSTOM) { - ODP_ERR("Too many custom fields\n"); - return ODP_LSO_PROFILE_INVALID; - } - - for (i = 0; i < num_custom; i++) { - mod_op = param->custom.field[i].mod_op; - offset = param->custom.field[i].offset; - size = param->custom.field[i].size; - - if (offset > PKTIO_LSO_MAX_PAYLOAD_OFFSET) { - ODP_ERR("Too large custom field offset %u\n", offset); + if (param->lso_proto == ODP_LSO_PROTO_CUSTOM) { + num_custom = param->custom.num_custom; + if (num_custom > ODP_LSO_MAX_CUSTOM) { + ODP_ERR("Too many custom fields\n"); return ODP_LSO_PROFILE_INVALID; } - /* Currently only segment number supported */ - if (mod_op != ODP_LSO_ADD_SEGMENT_NUM) { - ODP_ERR("Custom modify operation %u not supported\n", mod_op); - return ODP_LSO_PROFILE_INVALID; - } + for (i = 0; i < num_custom; i++) { + mod_op = param->custom.field[i].mod_op; + offset = param->custom.field[i].offset; + size = param->custom.field[i].size; - if (size != 1 && size != 2 && size != 4 && size != 8) { - ODP_ERR("Bad custom field size %u\n", size); - return ODP_LSO_PROFILE_INVALID; + if (offset > PKTIO_LSO_MAX_PAYLOAD_OFFSET) { + ODP_ERR("Too large custom field offset %u\n", offset); + return ODP_LSO_PROFILE_INVALID; + } + + /* Currently only segment number supported */ + if (mod_op != ODP_LSO_ADD_SEGMENT_NUM) { + ODP_ERR("Custom modify operation %u not supported\n", mod_op); + return ODP_LSO_PROFILE_INVALID; + } + + if (size != 1 && size != 2 && size != 4 && size != 8) { + ODP_ERR("Bad custom field size %u\n", size); + return ODP_LSO_PROFILE_INVALID; + } } } @@ -2624,6 +2628,32 @@ int odp_packet_lso_request(odp_packet_t pkt, const odp_packet_lso_opt_t *lso_opt return 0; } +static int lso_update_ipv4(odp_packet_t pkt, int index, int num_pkt, + uint32_t l3_offset, uint32_t payload_len) +{ + _odp_ipv4hdr_t *ipv4; + uint32_t pkt_len = odp_packet_len(pkt); + uint16_t tot_len = pkt_len - l3_offset; + int ret = 0; + uint16_t frag_offset; + + odp_packet_l3_offset_set(pkt, l3_offset); + ipv4 = odp_packet_l3_ptr(pkt, NULL); + ipv4->tot_len = odp_cpu_to_be_16(tot_len); + + /* IP payload offset in 8 byte blocks */ + frag_offset = ((uint32_t)index * payload_len) / 8; + + /* More fragments flag */ + if (index < (num_pkt - 1)) + frag_offset |= _ODP_IPV4HDR_FRAG_OFFSET_MORE_FRAGS; + + ipv4->frag_offset = odp_cpu_to_be_16(frag_offset); + ret = _odp_packet_ipv4_chksum_insert(pkt); + + return ret; +} + static int lso_update_custom(lso_profile_t *lso_prof, odp_packet_t pkt, int segnum) { void *ptr; @@ -2682,12 +2712,14 @@ static int pktout_send_lso(odp_pktout_queue_t queue, odp_packet_t packet, odp_packet_t pkt; int i, ret, num, num_pkt, num_full; uint32_t hdr_len, pkt_len, pkt_payload, payload_len, left_over_len, offset; + uint32_t l3_offset, iphdr_len; int left_over = 0; int num_free = 0; int first_free = 0; odp_lso_profile_t lso_profile = lso_opt->lso_profile; lso_profile_t *lso_prof = lso_profile_ptr(lso_profile); int num_custom = lso_prof->param.custom.num_custom; + odp_lso_protocol_t lso_proto = lso_prof->param.lso_proto; payload_len = lso_opt->max_payload_len; hdr_len = lso_opt->payload_offset; @@ -2704,6 +2736,24 @@ static int pktout_send_lso(odp_pktout_queue_t queue, odp_packet_t packet, return -1; } + if (lso_proto == ODP_LSO_PROTO_IPV4) { + l3_offset = odp_packet_l3_offset(packet); + iphdr_len = hdr_len - l3_offset; + + if (l3_offset == ODP_PACKET_OFFSET_INVALID) { + ODP_ERR("Invalid L3 offset\n"); + return -1; + } + + if (hdr_len < l3_offset || iphdr_len < _ODP_IPV4HDR_LEN) { + ODP_ERR("Bad payload or L3 offset\n"); + return -1; + } + + /* Round down payload len to a multiple of 8 (on other than the last fragment). */ + payload_len = (payload_len / 8) * 8; + } + pool = odp_packet_pool(packet); pkt_len = hdr_len + payload_len; num_pkt = pkt_payload / payload_len; @@ -2766,13 +2816,31 @@ static int pktout_send_lso(odp_pktout_queue_t queue, odp_packet_t packet, } } - /* Update custom fields */ - for (i = 0; num_custom && i < num_pkt; i++) { - if (lso_update_custom(lso_prof, pkt_out[i], i)) { - ODP_ERR("Custom field update failed. Segment %i\n", i); + if (lso_proto == ODP_LSO_PROTO_IPV4) { + l3_offset = odp_packet_l3_offset(packet); + + if (l3_offset == ODP_PACKET_OFFSET_INVALID) { + ODP_ERR("Invalid L3 offset\n"); num_free = num_pkt; goto error; } + + for (i = 0; i < num_pkt; i++) { + if (lso_update_ipv4(pkt_out[i], i, num_pkt, l3_offset, payload_len)) { + ODP_ERR("IPv4 header update failed. Packet %i.\n", i); + num_free = num_pkt; + goto error; + } + } + } else { + /* Update custom fields */ + for (i = 0; num_custom && i < num_pkt; i++) { + if (lso_update_custom(lso_prof, pkt_out[i], i)) { + ODP_ERR("Custom field update failed. Segment %i\n", i); + num_free = num_pkt; + goto error; + } + } } ret = odp_pktout_send(queue, pkt_out, num_pkt); -- cgit v1.2.3 From bb16313e5f607ce79ab541aafb226ee7055b0af2 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Tue, 29 Dec 2020 17:22:04 +0200 Subject: validation: pktio: add LSO IPv4 fragmentation test Added test case for LSO IPv4 fragmentation (ODP_LSO_PROTO_IPV4). Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- test/common/test_packet_parser.h | 192 +++++++++++++++++++++++++++++++++++++++ test/validation/api/pktio/lso.c | 128 ++++++++++++++++++++++++++ 2 files changed, 320 insertions(+) diff --git a/test/common/test_packet_parser.h b/test/common/test_packet_parser.h index 22e60de23..07e2cfe0a 100644 --- a/test/common/test_packet_parser.h +++ b/test/common/test_packet_parser.h @@ -577,6 +577,198 @@ static const uint8_t test_packet_ipv4_rr_nop_icmp[] = { 0x00, 0x00 }; +/* Ethernet/IPv4/UDP packet. Ethernet frame length 1500 bytes (+ CRC). */ +static const uint8_t test_packet_ipv4_udp_1500[] = { + 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x04, 0x00, 0x08, 0x00, 0x45, 0x00, + 0x05, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, + 0xF1, 0xCB, 0xC0, 0xA8, 0x01, 0x02, 0xC0, 0xA8, + 0x01, 0x01, 0x00, 0x3F, 0x00, 0x3F, 0x05, 0xBA, + 0xF8, 0x59, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, + 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, + 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, + 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, + 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, + 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, + 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, + 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, + 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, + 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, + 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, + 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, + 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, + 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, + 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, + 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, + 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, + 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, + 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, + 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, + 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, + 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, + 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, + 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, + 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, + 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, + 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, + 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, + 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, + 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, + 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, + 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, + 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, + 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, + 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, + 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, + 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, + 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, + 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, + 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, + 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, + 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, + 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, + 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, + 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, + 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, + 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, + 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, + 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, + 0xAE, 0xAF, 0xB0, 0xB1 +}; + #ifdef __cplusplus } #endif diff --git a/test/validation/api/pktio/lso.c b/test/validation/api/pktio/lso.c index 4020d1db5..6ace8d88c 100644 --- a/test/validation/api/pktio/lso.c +++ b/test/validation/api/pktio/lso.c @@ -21,6 +21,7 @@ /* Max payload bytes per LSO segment */ #define CUSTOM_MAX_PAYLOAD 288 +#define IPV4_MAX_PAYLOAD 700 /* Pktio interface info */ @@ -55,6 +56,9 @@ static int wait_for_network; /* LSO test packet pool */ odp_pool_t lso_pool = ODP_POOL_INVALID; +/* Check test packet size */ +ODP_STATIC_ASSERT(sizeof(test_packet_ipv4_udp_1500) == 1500, "error: size is not 1500"); + static inline void wait_linkup(odp_pktio_t pktio) { /* wait 1 second for link up */ @@ -474,6 +478,30 @@ static int check_lso_custom_restart(void) return ODP_TEST_ACTIVE; } +static int check_lso_ipv4(void) +{ + if (pktio_a->capa.lso.max_profiles == 0 || pktio_a->capa.lso.max_profiles_per_pktio == 0) + return ODP_TEST_INACTIVE; + + if (pktio_a->capa.lso.proto.ipv4 == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int check_lso_ipv4_restart(void) +{ + if (check_lso_ipv4() == ODP_TEST_INACTIVE) + return ODP_TEST_INACTIVE; + + if (disable_restart && num_starts > 0) + return ODP_TEST_INACTIVE; + + num_starts++; + + return ODP_TEST_ACTIVE; +} + static void lso_capability(void) { /* LSO not supported when max_profiles is zero */ @@ -498,6 +526,23 @@ static void lso_capability(void) } } +static void lso_create_ipv4_profile(void) +{ + odp_lso_profile_param_t param; + odp_lso_profile_t profile; + + odp_lso_profile_param_init(¶m); + CU_ASSERT(param.lso_proto == ODP_LSO_PROTO_NONE); + CU_ASSERT(param.custom.num_custom == 0); + + param.lso_proto = ODP_LSO_PROTO_IPV4; + + profile = odp_lso_profile_create(pktio_a->hdl, ¶m); + CU_ASSERT_FATAL(profile != ODP_LSO_PROFILE_INVALID); + + CU_ASSERT_FATAL(odp_lso_profile_destroy(profile) == 0); +} + static void lso_create_custom_profile(void) { odp_lso_profile_param_t param_0, param_1; @@ -668,9 +713,92 @@ static void lso_send_custom_eth_use_opt(void) lso_send_custom_eth(1); } +static void lso_send_ipv4(int use_opt) +{ + int i, ret, num; + odp_lso_profile_param_t param; + odp_lso_profile_t profile; + uint32_t offset, len, payload_len, payload_sum; + odp_packet_t packet[MAX_NUM_SEG]; + /* Ethernet 14B + IPv4 header 20B */ + uint32_t hdr_len = 34; + uint32_t pkt_len = sizeof(test_packet_ipv4_udp_1500); + uint32_t sent_payload = pkt_len - hdr_len; + uint32_t max_payload = IPV4_MAX_PAYLOAD; + + odp_lso_profile_param_init(¶m); + param.lso_proto = ODP_LSO_PROTO_IPV4; + + profile = odp_lso_profile_create(pktio_a->hdl, ¶m); + CU_ASSERT_FATAL(profile != ODP_LSO_PROFILE_INVALID); + + CU_ASSERT_FATAL(start_interfaces() == 0); + + test_lso_request_clear(profile, test_packet_ipv4_udp_1500, pkt_len, hdr_len, max_payload); + + ret = send_packets(profile, pktio_a, pktio_b, test_packet_ipv4_udp_1500, + pkt_len, hdr_len, max_payload, 14, use_opt); + CU_ASSERT_FATAL(ret == 0); + + ODPH_DBG("\n Sent payload length: %u bytes\n", sent_payload); + + /* Wait 1 sec to receive all created segments. Timeout and MAX_NUM_SEG values should be + * large enough to ensure that we receive all created segments. */ + num = recv_packets(pktio_b, ODP_TIME_SEC_IN_NS, packet, MAX_NUM_SEG); + CU_ASSERT(num > 0); + CU_ASSERT(num < MAX_NUM_SEG); + + offset = hdr_len; + payload_sum = 0; + for (i = 0; i < num; i++) { + len = odp_packet_len(packet[i]); + payload_len = len - hdr_len; + + ODPH_DBG(" LSO segment[%i] payload: %u bytes\n", i, payload_len); + + CU_ASSERT(odp_packet_has_ipv4(packet[i])); + CU_ASSERT(odp_packet_has_ipfrag(packet[i])); + CU_ASSERT(odp_packet_has_error(packet[i]) == 0); + CU_ASSERT(payload_len <= IPV4_MAX_PAYLOAD); + + if (compare_data(packet[i], hdr_len, + test_packet_ipv4_udp_1500 + offset, payload_len) >= 0) { + ODPH_ERR(" Payload compare failed at offset %u\n", offset); + CU_FAIL("Payload compare failed\n"); + } + + offset += payload_len; + payload_sum += payload_len; + } + + ODPH_DBG(" Received payload length: %u bytes\n", payload_sum); + + CU_ASSERT(payload_sum == sent_payload); + + if (num > 0) + odp_packet_free_multi(packet, num); + + CU_ASSERT_FATAL(stop_interfaces() == 0); + + CU_ASSERT_FATAL(odp_lso_profile_destroy(profile) == 0); +} + +static void lso_send_ipv4_use_pkt_meta(void) +{ + lso_send_ipv4(0); +} + +static void lso_send_ipv4_use_opt(void) +{ + lso_send_ipv4(1); +} + odp_testinfo_t lso_suite[] = { ODP_TEST_INFO(lso_capability), + ODP_TEST_INFO_CONDITIONAL(lso_create_ipv4_profile, check_lso_ipv4), ODP_TEST_INFO_CONDITIONAL(lso_create_custom_profile, check_lso_custom), + ODP_TEST_INFO_CONDITIONAL(lso_send_ipv4_use_pkt_meta, check_lso_ipv4_restart), + ODP_TEST_INFO_CONDITIONAL(lso_send_ipv4_use_opt, check_lso_ipv4_restart), ODP_TEST_INFO_CONDITIONAL(lso_send_custom_eth_use_pkt_meta, check_lso_custom_restart), ODP_TEST_INFO_CONDITIONAL(lso_send_custom_eth_use_opt, check_lso_custom_restart), ODP_TEST_INFO_NULL -- cgit v1.2.3 From de85637a4e41ab6e412f845a51ac76ac7dbec7ba Mon Sep 17 00:00:00 2001 From: Anoob Joseph Date: Wed, 27 Jan 2021 07:39:59 +0000 Subject: api: packet_io: enable inbound ipsec in pktio only after IPsec config IPsec configuration specifies the IPsec parameters that defines the inline inbound operation parameters such as number of SAs and SPI range. Hence, IPsec configuration must be done before enabling the flag in pktio_config. Signed-off-by: Anoob Joseph Reviewed-by: Janne Peltonen --- include/odp/api/spec/packet_io.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h index a6369acdf..0b6c95033 100644 --- a/include/odp/api/spec/packet_io.h +++ b/include/odp/api/spec/packet_io.h @@ -575,7 +575,8 @@ typedef struct odp_pktio_config_t { * * Enable/disable inline inbound IPSEC operation. When enabled packet * input directs all IPSEC packets automatically to IPSEC inbound - * processing. IPSEC configuration is done through the IPSEC API. + * processing. IPSEC configuration (through IPSEC API) must be done + * before enabling this feature in pktio. * Packets that are not (recognized as) IPSEC are processed * according to the packet input configuration. * -- cgit v1.2.3 From 4ef0fd28d1fbd992fbbd60a95740c2977a020166 Mon Sep 17 00:00:00 2001 From: Anoob Joseph Date: Tue, 2 Feb 2021 10:40:54 +0000 Subject: doc: userguide: update ipsec config dependency for pktio inline inbound Update documentation to reflect latest API semantics. Signed-off-by: Anoob Joseph Reviewed-by: Janne Peltonen --- doc/users-guide/users-guide-pktio.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/users-guide/users-guide-pktio.adoc b/doc/users-guide/users-guide-pktio.adoc index 4727323bf..5d9727d59 100644 --- a/doc/users-guide/users-guide-pktio.adoc +++ b/doc/users-guide/users-guide-pktio.adoc @@ -200,7 +200,8 @@ typedef struct odp_pktio_config_t { * * Enable/disable inline inbound IPSEC operation. When enabled packet * input directs all IPSEC packets automatically to IPSEC inbound - * processing. IPSEC configuration is done through the IPSEC API. + * processing. IPSEC configuration (through IPSEC API) must be done + * before enabling this feature in pktio. * Packets that are not (recognized as) IPSEC are processed * according to the packet input configuration. * -- cgit v1.2.3 From 42c93852338b2ab971c68361805c014ed7f6293e Mon Sep 17 00:00:00 2001 From: Anoob Joseph Date: Mon, 18 Jan 2021 13:14:09 +0000 Subject: validation: pktio: skip enabling inbound_ipsec Inbound IPsec processing in pktio can be enabled only if IPsec configuration is done prior. Hence, disable the same in pktio config test which attempts to enable all supported features. Signed-off-by: Anoob Joseph Signed-off-by: Vidya Reviewed-by: Janne Peltonen --- test/validation/api/pktio/pktio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/validation/api/pktio/pktio.c b/test/validation/api/pktio/pktio.c index 92c3f4ab0..074184a0b 100644 --- a/test/validation/api/pktio/pktio.c +++ b/test/validation/api/pktio/pktio.c @@ -1566,6 +1566,10 @@ static void pktio_test_pktio_config(void) CU_ASSERT_FATAL(odp_pktio_capability(pktio, &capa) == 0); config = capa.config; + + /* Disable inbound_ipsec as it requires IPsec config to be done */ + config.inbound_ipsec = 0; + CU_ASSERT(odp_pktio_config(pktio, &config) == 0); CU_ASSERT_FATAL(odp_pktio_close(pktio) == 0); -- cgit v1.2.3 From 988fb2cf1ff202ec883f9f4871ec238a54312c0c Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 31 Dec 2020 10:46:09 +0200 Subject: api: sched: allow only ODP_SCHED_NO_WAIT calls after odp_schedule_pause() Add limitation to odp_schedule_pause() documentation that calling only ODP_SCHED_NO_WAIT variants of schedule calls is allowed after calling odp_schedule_pause(). Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- include/odp/api/spec/schedule.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/odp/api/spec/schedule.h b/include/odp/api/spec/schedule.h index 716c09f51..b579a4090 100644 --- a/include/odp/api/spec/schedule.h +++ b/include/odp/api/spec/schedule.h @@ -157,13 +157,27 @@ int odp_schedule_multi_no_wait(odp_queue_t *from, odp_event_t events[], /** * Pause scheduling * - * Pause global scheduling for this thread. After this call, all schedule calls - * will return only locally pre-scheduled events (if any). User can exit the - * schedule loop only after the schedule function indicates that there's no more - * (pre-scheduled) events. - * - * Must be used with odp_schedule() and odp_schedule_multi() before exiting (or - * stalling) the schedule loop. + * Pause global scheduling for this thread. After this call, only + * ODP_SCHED_NO_WAIT schedule calls are allowed and these calls will return only + * locally pre-scheduled events (if any). User can exit the schedule loop only + * after the schedule function indicates that there's no more (pre-scheduled) + * events. + * + * Example call pattern: + * + * while (!stop) { + * odp_event_t ev = odp_schedule(NULL, ODP_SCHED_WAIT); + * // Process event + * } + * + * odp_schedule_pause(); + * + * while (1) { + * odp_event_t ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT); + * if (ev == ODP_EVENT_INVALID) + * break; + * odp_event_free(ev); + * } */ void odp_schedule_pause(void); -- cgit v1.2.3 From 41bee0ac9b161fd45bdaabf0e127630f4181d427 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 31 Dec 2020 11:05:02 +0200 Subject: validation: sched: don't call schedule with wait after pause Update validation test to follow the updated odp_schedule_pause() API and only call schedule with ODP_SCHED_NO_WAIT after calling pause. Signed-off-by: Matias Elo Tested-by: Shijith Thotton Reviewed-by: Petri Savolainen --- test/validation/api/scheduler/scheduler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/validation/api/scheduler/scheduler.c b/test/validation/api/scheduler/scheduler.c index 6b8e30559..461d00ebd 100644 --- a/test/validation/api/scheduler/scheduler.c +++ b/test/validation/api/scheduler/scheduler.c @@ -2177,7 +2177,7 @@ static int sched_and_plain_thread(void *arg) /* Make sure scheduling context is released */ odp_schedule_pause(); - while ((ev1 = odp_schedule(NULL, wait)) != ODP_EVENT_INVALID) { + while ((ev1 = odp_schedule(NULL, ODP_SCHED_NO_WAIT)) != ODP_EVENT_INVALID) { if (sync == ODP_SCHED_SYNC_ORDERED) odp_schedule_order_lock(0); -- cgit v1.2.3 From a880bce6241bfdb7a5344538a323732861a70660 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 31 Dec 2020 11:46:59 +0200 Subject: api: sched: add configure option to enable/disable predefined sched groups Add new configuration options to odp_schedule_config_t, which allow user to enable/disable standard predefined scheduling groups (ODP_SCHED_GROUP_ALL, ODP_SCHED_GROUP_WORKER, ODP_SCHED_GROUP_CONTROL). All groups are enable by default to maintain backward compatibility. Fixed a typo in odp_schedule_config_t. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- include/odp/api/spec/schedule.h | 8 ++++---- include/odp/api/spec/schedule_types.h | 29 +++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/include/odp/api/spec/schedule.h b/include/odp/api/spec/schedule.h index b579a4090..9e96e0684 100644 --- a/include/odp/api/spec/schedule.h +++ b/include/odp/api/spec/schedule.h @@ -340,10 +340,10 @@ int odp_schedule_capability(odp_schedule_capability_t *capa); * Creates a schedule group with the thread mask. Only threads in the * mask will receive events from a queue that belongs to the schedule group. * Thread masks of various schedule groups may overlap. There are predefined - * groups such as ODP_SCHED_GROUP_ALL and ODP_SCHED_GROUP_WORKER, which are - * always present and automatically updated. The use of group name is optional. - * Unique names are not required. However, odp_schedule_group_lookup() returns - * only a single matching group. + * groups, such as ODP_SCHED_GROUP_ALL and ODP_SCHED_GROUP_WORKER, which are + * present by default and are automatically updated. The use of group name is + * optional. Unique names are not required. However, odp_schedule_group_lookup() + * returns only a single matching group. * * @param name Name of the schedule group or NULL. Maximum string length is * ODP_SCHED_GROUP_NAME_LEN. diff --git a/include/odp/api/spec/schedule_types.h b/include/odp/api/spec/schedule_types.h index c53259012..a8507cd26 100644 --- a/include/odp/api/spec/schedule_types.h +++ b/include/odp/api/spec/schedule_types.h @@ -253,13 +253,38 @@ typedef struct odp_schedule_config_t { * scheduling of the event and synchronization is maintained per flow * within each queue. * - * Depeding on implementation, there may be much more flows supported - * than queues, as flows are lightweight entities. + * Depending on the implementation, there may be much more flows + * supported than queues, as flows are lightweight entities. * * @see odp_schedule_capability_t, odp_event_flow_id() */ uint32_t max_flow_id; + /** Enable/disable predefined scheduling groups */ + struct { + /** ODP_SCHED_GROUP_ALL + * + * 0: Disable group + * 1: Enable group (default) + */ + odp_bool_t all; + + /** ODP_SCHED_GROUP_CONTROL + * + * 0: Disable group + * 1: Enable group (default) + */ + odp_bool_t control; + + /** ODP_SCHED_GROUP_WORKER + * + * 0: Disable group + * 1: Enable group (default) + */ + odp_bool_t worker; + + } sched_group; + } odp_schedule_config_t; /** -- cgit v1.2.3 From 877f2bbe569740e1cb63fbc6c7c0e2b74eb464ea Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Tue, 29 Dec 2020 15:59:19 +0200 Subject: api: sched: clarify max_groups capability definition Extend odp_schedule_capability_t.max_groups definition to state that the value is the total number of scheduling groups (includes the enabled predefined scheduling groups). Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- include/odp/api/spec/schedule_types.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/odp/api/spec/schedule_types.h b/include/odp/api/spec/schedule_types.h index a8507cd26..90146585f 100644 --- a/include/odp/api/spec/schedule_types.h +++ b/include/odp/api/spec/schedule_types.h @@ -190,7 +190,10 @@ typedef struct odp_schedule_capability_t { /** Maximum number of ordered locks per queue */ uint32_t max_ordered_locks; - /** Maximum number of scheduling groups */ + /** Maximum number of scheduling groups. The value includes the enabled + * predefined scheduling groups (ODP_SCHED_GROUP_ALL, + * ODP_SCHED_GROUP_WORKER, and ODP_SCHED_GROUP_CONTROL). By default, an + * application can create 'max_groups' - 3 groups. */ uint32_t max_groups; /** Number of scheduling priorities */ -- cgit v1.2.3 From 16a77c75f85677c7944a5b9612475e0dac40d249 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Mon, 4 Jan 2021 16:49:20 +0200 Subject: linux-gen: sched_basic: implement disabling predefined sched groups Implement odp_schedule_config_t.sched_group option for the basic scheduler. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- config/odp-linux-generic.conf | 2 + platform/linux-generic/odp_schedule_basic.c | 65 ++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/config/odp-linux-generic.conf b/config/odp-linux-generic.conf index bb25c39b2..8469b72d7 100644 --- a/config/odp-linux-generic.conf +++ b/config/odp-linux-generic.conf @@ -179,6 +179,8 @@ sched_basic: { # Automatically updated schedule groups # + # DEPRECATED: use odp_schedule_config() API instead + # # API specification defines that ODP_SCHED_GROUP_ALL, # _WORKER and _CONTROL are updated automatically. These options can be # used to disable these group when not used. Set value to 0 to disable diff --git a/platform/linux-generic/odp_schedule_basic.c b/platform/linux-generic/odp_schedule_basic.c index 67a3f50cc..0396123f3 100644 --- a/platform/linux-generic/odp_schedule_basic.c +++ b/platform/linux-generic/odp_schedule_basic.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -529,6 +529,9 @@ static inline int grp_update_tbl(void) odp_spinlock_unlock(&sched->grp_lock); + if (odp_unlikely(num == 0)) + return 0; + /* Update group weights. Round robin over all thread's groups. */ for (i = 0; i < GRP_WEIGHT_TBL_SIZE; i++) sched_local.grp_weight[i] = i % num; @@ -584,6 +587,21 @@ static int schedule_create_queue(uint32_t queue_index, ODP_ERR("Bad schedule group\n"); return -1; } + if (sched_param->group == ODP_SCHED_GROUP_ALL && + !sched->config_if.group_enable.all) { + ODP_ERR("Trying to use disabled ODP_SCHED_GROUP_ALL\n"); + return -1; + } + if (sched_param->group == ODP_SCHED_GROUP_CONTROL && + !sched->config_if.group_enable.control) { + ODP_ERR("Trying to use disabled ODP_SCHED_GROUP_CONTROL\n"); + return -1; + } + if (sched_param->group == ODP_SCHED_GROUP_WORKER && + !sched->config_if.group_enable.worker) { + ODP_ERR("Trying to use disabled ODP_SCHED_GROUP_WORKER\n"); + return -1; + } odp_spinlock_lock(&sched->mask_lock); @@ -806,11 +824,44 @@ static void schedule_config_init(odp_schedule_config_t *config) { config->num_queues = CONFIG_MAX_SCHED_QUEUES; config->queue_size = _odp_queue_glb->config.max_queue_size; + config->sched_group.all = sched->config_if.group_enable.all; + config->sched_group.control = sched->config_if.group_enable.control; + config->sched_group.worker = sched->config_if.group_enable.worker; +} + +static void schedule_group_clear(odp_schedule_group_t group) +{ + odp_thrmask_t zero; + + odp_thrmask_zero(&zero); + + if (group < 0 || group > ODP_SCHED_GROUP_CONTROL) + ODP_ABORT("Invalid scheduling group\n"); + + grp_update_mask(group, &zero); + sched->sched_grp[group].allocated = 0; + } static int schedule_config(const odp_schedule_config_t *config) { - (void)config; + odp_spinlock_lock(&sched->grp_lock); + + sched->config_if.group_enable.all = config->sched_group.all; + sched->config_if.group_enable.control = config->sched_group.control; + sched->config_if.group_enable.worker = config->sched_group.worker; + + /* Remove existing threads from predefined scheduling groups. */ + if (!config->sched_group.all) + schedule_group_clear(ODP_SCHED_GROUP_ALL); + + if (!config->sched_group.worker) + schedule_group_clear(ODP_SCHED_GROUP_WORKER); + + if (!config->sched_group.control) + schedule_group_clear(ODP_SCHED_GROUP_CONTROL); + + odp_spinlock_unlock(&sched->grp_lock); return 0; } @@ -1530,6 +1581,11 @@ static int schedule_thr_add(odp_schedule_group_t group, int thr) odp_spinlock_lock(&sched->grp_lock); + if (!sched->sched_grp[group].allocated) { + odp_spinlock_unlock(&sched->grp_lock); + return 0; + } + odp_thrmask_or(&new_mask, &sched->sched_grp[group].mask, &mask); grp_update_mask(group, &new_mask); @@ -1552,6 +1608,11 @@ static int schedule_thr_rem(odp_schedule_group_t group, int thr) odp_spinlock_lock(&sched->grp_lock); + if (!sched->sched_grp[group].allocated) { + odp_spinlock_unlock(&sched->grp_lock); + return 0; + } + odp_thrmask_and(&new_mask, &sched->sched_grp[group].mask, &new_mask); grp_update_mask(group, &new_mask); -- cgit v1.2.3 From cdb12fbf76fbe8da43e84afa78e0193225727064 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Tue, 5 Jan 2021 10:31:51 +0200 Subject: linux-gen: sched_sp: implement disabling predefined sched groups Implement odp_schedule_config_t.sched_group option for the SP scheduler. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/odp_schedule_sp.c | 69 ++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/platform/linux-generic/odp_schedule_sp.c b/platform/linux-generic/odp_schedule_sp.c index 08be438f4..90ba101cd 100644 --- a/platform/linux-generic/odp_schedule_sp.c +++ b/platform/linux-generic/odp_schedule_sp.c @@ -1,5 +1,5 @@ /* Copyright (c) 2016-2018, Linaro Limited - * Copyright (c) 2019-2020, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -125,6 +125,8 @@ typedef struct { prio_queue_t prio_queue[NUM_GROUP][NUM_PRIO]; sched_group_t sched_group; odp_shm_t shm; + /* Scheduler interface config options (not used in fast path) */ + schedule_config_t config_if; } sched_global_t; typedef struct { @@ -139,6 +141,8 @@ typedef struct { static sched_global_t *sched_global; static __thread sched_local_t sched_local; +static void remove_group(sched_group_t *sched_group, int thr, int group); + static inline uint32_t index_to_ring_idx(int pktio, uint32_t index) { if (pktio) @@ -220,6 +224,10 @@ static int init_global(void) odp_thrmask_zero(&sched_group->s.group[GROUP_CONTROL].mask); sched_group->s.group[GROUP_CONTROL].allocated = 1; + sched_global->config_if.group_enable.all = 1; + sched_global->config_if.group_enable.control = 1; + sched_global->config_if.group_enable.worker = 1; + return 0; } @@ -269,11 +277,52 @@ static void schedule_config_init(odp_schedule_config_t *config) { config->num_queues = CONFIG_MAX_SCHED_QUEUES; config->queue_size = _odp_queue_glb->config.max_queue_size; + config->sched_group.all = true; + config->sched_group.control = true; + config->sched_group.worker = true; +} + +static void schedule_group_clear(odp_schedule_group_t group) +{ + sched_group_t *sched_group = &sched_global->sched_group; + int thr; + const odp_thrmask_t *thrmask; + + if (group < 0 || group >= NUM_STATIC_GROUP) + ODP_ABORT("Invalid scheduling group\n"); + + thrmask = &sched_group->s.group[group].mask; + + thr = odp_thrmask_first(thrmask); + while (thr >= 0) { + remove_group(sched_group, thr, group); + thr = odp_thrmask_next(thrmask, thr); + } + + memset(&sched_group->s.group[group], 0, sizeof(sched_group->s.group[0])); } static int schedule_config(const odp_schedule_config_t *config) { - (void)config; + sched_group_t *sched_group = &sched_global->sched_group; + + odp_ticketlock_lock(&sched_group->s.lock); + + sched_global->config_if.group_enable.all = config->sched_group.all; + sched_global->config_if.group_enable.control = config->sched_group.control; + sched_global->config_if.group_enable.worker = config->sched_group.worker; + + /* Remove existing threads from predefined scheduling groups. */ + if (!config->sched_group.all) + schedule_group_clear(ODP_SCHED_GROUP_ALL); + + if (!config->sched_group.worker) + schedule_group_clear(ODP_SCHED_GROUP_WORKER); + + if (!config->sched_group.control) + schedule_group_clear(ODP_SCHED_GROUP_CONTROL); + + odp_ticketlock_unlock(&sched_group->s.lock); return 0; } @@ -334,7 +383,7 @@ static int thr_add(odp_schedule_group_t group, int thr) { sched_group_t *sched_group = &sched_global->sched_group; - if (group < 0 || group >= NUM_GROUP) + if (group < 0 || group >= NUM_STATIC_GROUP) return -1; if (thr < 0 || thr >= NUM_THREAD) @@ -344,7 +393,7 @@ static int thr_add(odp_schedule_group_t group, int thr) if (!sched_group->s.group[group].allocated) { odp_ticketlock_unlock(&sched_group->s.lock); - return -1; + return 0; } odp_thrmask_set(&sched_group->s.group[group].mask, thr); @@ -359,14 +408,14 @@ static int thr_rem(odp_schedule_group_t group, int thr) { sched_group_t *sched_group = &sched_global->sched_group; - if (group < 0 || group >= NUM_GROUP) + if (group < 0 || group >= NUM_STATIC_GROUP) return -1; odp_ticketlock_lock(&sched_group->s.lock); if (!sched_group->s.group[group].allocated) { odp_ticketlock_unlock(&sched_group->s.lock); - return -1; + return 0; } odp_thrmask_clr(&sched_group->s.group[group].mask, thr); @@ -986,6 +1035,11 @@ static int schedule_capability(odp_schedule_capability_t *capa) return 0; } +static void get_config(schedule_config_t *config) +{ + *config = *(&sched_global->config_if); +}; + /* Fill in scheduler interface */ const schedule_fn_t _odp_schedule_sp_fn = { .pktio_start = pktio_start, @@ -1002,7 +1056,8 @@ const schedule_fn_t _odp_schedule_sp_fn = { .term_local = term_local, .order_lock = order_lock, .order_unlock = order_unlock, - .max_ordered_locks = max_ordered_locks + .max_ordered_locks = max_ordered_locks, + .get_config = get_config }; /* Fill in scheduler API calls */ -- cgit v1.2.3 From 021fae961617339338a587b373bbd29fd6e0b92a Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Tue, 5 Jan 2021 10:53:35 +0200 Subject: linux-gen: sched_scalable: implement disabling predefined sched groups Implement odp_schedule_config_t.sched_group option for the scalable scheduler. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/odp_schedule_scalable.c | 93 ++++++++++++++++++++------ 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/platform/linux-generic/odp_schedule_scalable.c b/platform/linux-generic/odp_schedule_scalable.c index 6d3cb6996..4da5c378d 100644 --- a/platform/linux-generic/odp_schedule_scalable.c +++ b/platform/linux-generic/odp_schedule_scalable.c @@ -60,9 +60,13 @@ typedef struct { sched_group_t *sg_vec[MAX_SCHED_GROUP]; /** Group lock for MT-safe APIs */ odp_spinlock_t sched_grp_lock; + /** Initialization lock */ + odp_spinlock_t init_lock; /** Per thread state */ sched_scalable_thread_state_t thread_state[MAXTHREADS]; uint16_t poll_count[ODP_CONFIG_PKTIO_ENTRIES]; + /* Scheduler interface config options (not used in fast path) */ + schedule_config_t config_if; } sched_global_t; static sched_global_t *global; @@ -1837,6 +1841,7 @@ static int schedule_init_global(void) global->sched_shm_pool = pool; odp_spinlock_init(&global->sched_grp_lock); + odp_spinlock_init(&global->init_lock); bits = MAX_SCHED_GROUP; if (MAX_SCHED_GROUP == sizeof(global->sg_free) * CHAR_BIT) @@ -1874,6 +1879,10 @@ static int schedule_init_global(void) goto failed_create_group_control; } + global->config_if.group_enable.all = 1; + global->config_if.group_enable.control = 1; + global->config_if.group_enable.worker = 1; + return 0; failed_create_group_control: @@ -1895,15 +1904,20 @@ failed_sched_shm_pool_create: static int schedule_term_global(void) { - /* Destroy sched groups for default GROUP_ALL, GROUP_WORKER and - * GROUP_CONTROL groups. - */ - if (odp_schedule_group_destroy(ODP_SCHED_GROUP_ALL) != 0) - ODP_ERR("Failed to destroy ODP_SCHED_GROUP_ALL\n"); - if (odp_schedule_group_destroy(ODP_SCHED_GROUP_WORKER) != 0) - ODP_ERR("Failed to destroy ODP_SCHED_GROUP_WORKER\n"); - if (odp_schedule_group_destroy(ODP_SCHED_GROUP_CONTROL) != 0) - ODP_ERR("Failed to destroy ODP_SCHED_GROUP_CONTROL\n"); + /* Destroy enabled sched groups for default GROUP_ALL, GROUP_WORKER and + * GROUP_CONTROL groups. */ + if (global->config_if.group_enable.all) { + if (odp_schedule_group_destroy(ODP_SCHED_GROUP_ALL) != 0) + ODP_ERR("Failed to destroy ODP_SCHED_GROUP_ALL\n"); + } + if (global->config_if.group_enable.worker) { + if (odp_schedule_group_destroy(ODP_SCHED_GROUP_WORKER) != 0) + ODP_ERR("Failed to destroy ODP_SCHED_GROUP_WORKER\n"); + } + if (global->config_if.group_enable.control) { + if (odp_schedule_group_destroy(ODP_SCHED_GROUP_CONTROL) != 0) + ODP_ERR("Failed to destroy ODP_SCHED_GROUP_CONTROL\n"); + } _odp_ishm_pool_destroy(global->sched_shm_pool); @@ -1930,17 +1944,22 @@ static int schedule_init_local(void) odp_thrmask_zero(&mask); odp_thrmask_set(&mask, thr_id); - if (odp_schedule_group_join(ODP_SCHED_GROUP_ALL, &mask) != 0) { - ODP_ERR("Failed to join ODP_SCHED_GROUP_ALL\n"); - goto failed_to_join_grp_all; + odp_spinlock_lock(&global->init_lock); + + if (global->config_if.group_enable.all) { + if (odp_schedule_group_join(ODP_SCHED_GROUP_ALL, &mask) != 0) { + ODP_ERR("Failed to join ODP_SCHED_GROUP_ALL\n"); + goto failed_to_join_grp_all; + } } - if (thr_type == ODP_THREAD_CONTROL) { + if (global->config_if.group_enable.control && thr_type == ODP_THREAD_CONTROL) { if (odp_schedule_group_join(ODP_SCHED_GROUP_CONTROL, &mask) != 0) { ODP_ERR("Failed to join ODP_SCHED_GROUP_CONTROL\n"); goto failed_to_join_grp_ctrl; } - } else { + } + if (global->config_if.group_enable.worker && thr_type == ODP_THREAD_WORKER) { if (odp_schedule_group_join(ODP_SCHED_GROUP_WORKER, &mask) != 0) { ODP_ERR("Failed to join ODP_SCHED_GROUP_WORKER\n"); @@ -1948,16 +1967,19 @@ static int schedule_init_local(void) } } + odp_spinlock_unlock(&global->init_lock); + return 0; failed_to_join_grp_wrkr: - failed_to_join_grp_ctrl: - odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &mask); + if (global->config_if.group_enable.all) + odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &mask); failed_to_join_grp_all: -failed_to_init_ts: + odp_spinlock_unlock(&global->init_lock); +failed_to_init_ts: return -1; } @@ -1974,13 +1996,16 @@ static int schedule_term_local(void) odp_thrmask_zero(&mask); odp_thrmask_set(&mask, thr_id); - if (odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &mask) != 0) - ODP_ERR("Failed to leave ODP_SCHED_GROUP_ALL\n"); - if (thr_type == ODP_THREAD_CONTROL) { + if (global->config_if.group_enable.all) { + if (odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &mask) != 0) + ODP_ERR("Failed to leave ODP_SCHED_GROUP_ALL\n"); + } + if (global->config_if.group_enable.control && thr_type == ODP_THREAD_CONTROL) { if (odp_schedule_group_leave(ODP_SCHED_GROUP_CONTROL, &mask) != 0) ODP_ERR("Failed to leave ODP_SCHED_GROUP_CONTROL\n"); - } else { + } + if (global->config_if.group_enable.worker && thr_type == ODP_THREAD_WORKER) { if (odp_schedule_group_leave(ODP_SCHED_GROUP_WORKER, &mask) != 0) ODP_ERR("Failed to leave ODP_SCHED_GROUP_WORKER\n"); @@ -2002,11 +2027,35 @@ static void schedule_config_init(odp_schedule_config_t *config) { config->num_queues = CONFIG_MAX_SCHED_QUEUES; config->queue_size = 0; /* FIXME ? */ + config->sched_group.all = true; + config->sched_group.control = true; + config->sched_group.worker = true; } static int schedule_config(const odp_schedule_config_t *config) { - (void)config; + odp_spinlock_lock(&global->init_lock); + + global->config_if.group_enable.all = config->sched_group.all; + global->config_if.group_enable.control = config->sched_group.control; + global->config_if.group_enable.worker = config->sched_group.worker; + + /* Destroy disabled predefined scheduling groups. */ + if (!config->sched_group.all) { + if (odp_schedule_group_destroy(ODP_SCHED_GROUP_ALL) != 0) + ODP_ERR("Failed to destroy ODP_SCHED_GROUP_ALL\n"); + } + if (!config->sched_group.worker) { + if (odp_schedule_group_destroy(ODP_SCHED_GROUP_WORKER) != 0) + ODP_ERR("Failed to destroy ODP_SCHED_GROUP_WORKER\n"); + } + + if (!config->sched_group.control) { + if (odp_schedule_group_destroy(ODP_SCHED_GROUP_CONTROL) != 0) + ODP_ERR("Failed to destroy ODP_SCHED_GROUP_CONTROL\n"); + } + + odp_spinlock_unlock(&global->init_lock); return 0; } -- cgit v1.2.3 From c9d31e487ad03b97078df74a0613f461956aa965 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Mon, 4 Jan 2021 17:45:31 +0200 Subject: validation: sched: add tests for configuring default scheduling groups Add validation tests for the new odp_schedule_config_t.sched_group options. Since odp_schedule_config() can be called only once per run, a separate test application scheduler_no_predef_groups has been added. It configures scheduler with all predefined scheduling groups disabled. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- test/validation/api/Makefile.am | 1 + test/validation/api/scheduler/.gitignore | 1 + test/validation/api/scheduler/Makefile.am | 3 +- test/validation/api/scheduler/scheduler.c | 13 +- .../api/scheduler/scheduler_no_predef_groups.c | 225 +++++++++++++++++++++ 5 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 test/validation/api/scheduler/scheduler_no_predef_groups.c diff --git a/test/validation/api/Makefile.am b/test/validation/api/Makefile.am index 7ed00d922..8464ee027 100644 --- a/test/validation/api/Makefile.am +++ b/test/validation/api/Makefile.am @@ -61,6 +61,7 @@ TESTS = \ queue/queue_main$(EXEEXT) \ random/random_main$(EXEEXT) \ scheduler/scheduler_main$(EXEEXT) \ + scheduler/scheduler_no_predef_groups$(EXEEXT) \ stash/stash_main$(EXEEXT) \ std_clib/std_clib_main$(EXEEXT) \ thread/thread_main$(EXEEXT) \ diff --git a/test/validation/api/scheduler/.gitignore b/test/validation/api/scheduler/.gitignore index b4eb30091..6892e6224 100644 --- a/test/validation/api/scheduler/.gitignore +++ b/test/validation/api/scheduler/.gitignore @@ -1 +1,2 @@ scheduler_main +scheduler_no_predef_groups diff --git a/test/validation/api/scheduler/Makefile.am b/test/validation/api/scheduler/Makefile.am index 050f22308..fc41ae5fe 100644 --- a/test/validation/api/scheduler/Makefile.am +++ b/test/validation/api/scheduler/Makefile.am @@ -1,4 +1,5 @@ include ../Makefile.inc -test_PROGRAMS = scheduler_main +test_PROGRAMS = scheduler_main scheduler_no_predef_groups scheduler_main_SOURCES = scheduler.c +scheduler_no_predef_groups = scheduler_no_predef_groups.c diff --git a/test/validation/api/scheduler/scheduler.c b/test/validation/api/scheduler/scheduler.c index 461d00ebd..4cbede9cd 100644 --- a/test/validation/api/scheduler/scheduler.c +++ b/test/validation/api/scheduler/scheduler.c @@ -138,6 +138,16 @@ static void release_context(odp_schedule_sync_t sync) odp_schedule_release_ordered(); } +static void scheduler_test_init(void) +{ + odp_schedule_config_t default_config; + + odp_schedule_config_init(&default_config); + + CU_ASSERT(default_config.sched_group.all); + CU_ASSERT(default_config.sched_group.control); + CU_ASSERT(default_config.sched_group.worker); +} static void scheduler_test_capa(void) { odp_schedule_capability_t sched_capa; @@ -819,7 +829,7 @@ static void scheduler_test_create_max_groups(void) odp_schedule_capability_t sched_capa; CU_ASSERT_FATAL(!odp_schedule_capability(&sched_capa)); - uint32_t max_groups = sched_capa.max_groups; + uint32_t max_groups = sched_capa.max_groups - 3; /* Enabled predefined groups */ odp_schedule_group_t group[max_groups]; odp_queue_t queue[max_groups]; @@ -2851,6 +2861,7 @@ static void scheduler_test_flow_aware(void) /* Default scheduler config */ odp_testinfo_t scheduler_suite[] = { + ODP_TEST_INFO(scheduler_test_init), ODP_TEST_INFO(scheduler_test_capa), ODP_TEST_INFO(scheduler_test_wait_time), ODP_TEST_INFO(scheduler_test_num_prio), diff --git a/test/validation/api/scheduler/scheduler_no_predef_groups.c b/test/validation/api/scheduler/scheduler_no_predef_groups.c new file mode 100644 index 000000000..3dd79ebcc --- /dev/null +++ b/test/validation/api/scheduler/scheduler_no_predef_groups.c @@ -0,0 +1,225 @@ +/* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2019-2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "odp_cunit_common.h" +#include + +static int drain_queues(void) +{ + odp_event_t ev; + uint64_t wait = odp_schedule_wait_time(100 * ODP_TIME_MSEC_IN_NS); + int ret = 0; + + while ((ev = odp_schedule(NULL, wait)) != ODP_EVENT_INVALID) { + odp_event_free(ev); + ret++; + } + + return ret; +} + +static void scheduler_test_create_group(void) +{ + odp_thrmask_t mask; + odp_schedule_group_t group; + int thr_id; + odp_pool_t pool; + odp_pool_param_t pool_params; + odp_queue_t queue, from; + odp_queue_param_t qp; + odp_buffer_t buf; + odp_event_t ev; + uint64_t wait_time; + + thr_id = odp_thread_id(); + odp_thrmask_zero(&mask); + odp_thrmask_set(&mask, thr_id); + + group = odp_schedule_group_create("create_group", &mask); + CU_ASSERT_FATAL(group != ODP_SCHED_GROUP_INVALID); + + odp_pool_param_init(&pool_params); + pool_params.buf.size = 100; + pool_params.buf.num = 2; + pool_params.type = ODP_POOL_BUFFER; + + pool = odp_pool_create("create_group", &pool_params); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + odp_queue_param_init(&qp); + qp.type = ODP_QUEUE_TYPE_SCHED; + qp.sched.prio = odp_schedule_default_prio(); + qp.sched.sync = ODP_SCHED_SYNC_ATOMIC; + qp.sched.group = group; + + queue = odp_queue_create("create_group", &qp); + CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID); + + buf = odp_buffer_alloc(pool); + CU_ASSERT_FATAL(buf != ODP_BUFFER_INVALID); + + ev = odp_buffer_to_event(buf); + + CU_ASSERT_FATAL(odp_queue_enq(queue, ev) == 0); + + wait_time = odp_schedule_wait_time(100 * ODP_TIME_MSEC_IN_NS); + ev = odp_schedule(&from, wait_time); + + CU_ASSERT(ev != ODP_EVENT_INVALID); + CU_ASSERT(from == queue); + + if (ev != ODP_EVENT_INVALID) + odp_event_free(ev); + + /* Free schedule context */ + drain_queues(); + + CU_ASSERT_FATAL(odp_queue_destroy(queue) == 0); + CU_ASSERT_FATAL(odp_pool_destroy(pool) == 0); + CU_ASSERT_FATAL(odp_schedule_group_destroy(group) == 0); + + /* Run scheduler after the group has been destroyed */ + CU_ASSERT_FATAL(odp_schedule(NULL, wait_time) == ODP_EVENT_INVALID); +} + +static void scheduler_test_create_max_groups(void) +{ + odp_thrmask_t mask; + int thr_id; + uint32_t i; + odp_queue_param_t queue_param; + odp_schedule_capability_t sched_capa; + + CU_ASSERT_FATAL(!odp_schedule_capability(&sched_capa)); + uint32_t max_groups = sched_capa.max_groups; + odp_schedule_group_t group[max_groups]; + odp_queue_t queue[max_groups]; + + CU_ASSERT_FATAL(max_groups > 0); + CU_ASSERT_FATAL(sched_capa.max_queues >= sched_capa.max_groups); + + thr_id = odp_thread_id(); + odp_thrmask_zero(&mask); + odp_thrmask_set(&mask, thr_id); + + odp_queue_param_init(&queue_param); + queue_param.type = ODP_QUEUE_TYPE_SCHED; + queue_param.sched.prio = odp_schedule_default_prio(); + queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC; + + for (i = 0; i < max_groups; i++) { + group[i] = odp_schedule_group_create("max_groups", &mask); + if (group[i] == ODP_SCHED_GROUP_INVALID) { + ODPH_ERR("schedule group create %u failed\n", i); + break; + } + + queue_param.sched.group = group[i]; + queue[i] = odp_queue_create("max_groups", &queue_param); + CU_ASSERT_FATAL(queue[i] != ODP_QUEUE_INVALID); + } + + CU_ASSERT(i == max_groups); + max_groups = i; + + for (i = 0; i < max_groups; i++) { + CU_ASSERT_FATAL(odp_queue_destroy(queue[i]) == 0); + CU_ASSERT_FATAL(odp_schedule_group_destroy(group[i]) == 0); + } +} + +static int scheduler_suite_init(void) +{ + odp_schedule_capability_t sched_capa; + odp_schedule_config_t sched_config; + + if (odp_schedule_capability(&sched_capa)) { + printf("odp_schedule_capability() failed\n"); + return -1; + } + + odp_schedule_config_init(&sched_config); + + /* Disable all predefined groups */ + sched_config.sched_group.all = false; + sched_config.sched_group.control = false; + sched_config.sched_group.worker = false; + + /* Configure the scheduler. All test cases share the config. */ + if (odp_schedule_config(&sched_config)) { + printf("odp_schedule_config() failed.\n"); + return -1; + } + + return 0; +} + +static int scheduler_suite_term(void) +{ + if (odp_cunit_print_inactive()) + return -1; + + return 0; +} + +/* Default scheduler config */ +odp_testinfo_t scheduler_suite[] = { + ODP_TEST_INFO(scheduler_test_create_group), + ODP_TEST_INFO(scheduler_test_create_max_groups), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t scheduler_suites[] = { + {"Scheduler no predefined groups", + scheduler_suite_init, scheduler_suite_term, scheduler_suite + }, + ODP_SUITE_INFO_NULL, +}; + +static int global_init(odp_instance_t *inst) +{ + odp_init_t init_param; + odph_helper_options_t helper_options; + + if (odph_options(&helper_options)) { + ODPH_ERR("odph_options() failed.\n"); + return -1; + } + + odp_init_param_init(&init_param); + init_param.mem_model = helper_options.mem_model; + + if (odp_init_global(inst, &init_param, NULL)) { + ODPH_ERR("odp_init_global() failed.\n"); + return -1; + } + + if (odp_init_local(*inst, ODP_THREAD_CONTROL)) { + ODPH_ERR("odp_init_local() failed.\n"); + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(argc, argv)) + return -1; + + odp_cunit_register_global_init(global_init); + ret = odp_cunit_register(scheduler_suites); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} -- cgit v1.2.3 From 34a5483a08f70e67e32d5e249b76d1eed62afba7 Mon Sep 17 00:00:00 2001 From: Satheesh Paul Date: Tue, 12 Jan 2021 11:02:16 +0530 Subject: validation: cls: fix GTP test by changing seqno location One GTP-u PMR test creates a GTP packet but then changes the UDP port which makes cls_pkt_get_seq() treat the packet as a plain UDP packet, causing it to read the test packet sequence number from a wrong location. Fix the problem and simplify the sequence number functions by storing the sequence number in the last bytes of the packet regardless of packet type. Signed-off-by: Satheesh Paul Reviewed-by: Janne Peltonen --- .../api/classification/odp_classification_common.c | 114 +++++++-------------- 1 file changed, 38 insertions(+), 76 deletions(-) diff --git a/test/validation/api/classification/odp_classification_common.c b/test/validation/api/classification/odp_classification_common.c index b7a4b84ba..dfbafc687 100644 --- a/test/validation/api/classification/odp_classification_common.c +++ b/test/validation/api/classification/odp_classification_common.c @@ -91,98 +91,60 @@ int stop_pktio(odp_pktio_t pktio) return 0; } +static uint32_t seqno_offset(odp_packet_t pkt) +{ + uint32_t l3_offset = odp_packet_l3_offset(pkt); + int rc; + uint16_t len = 0; + + CU_ASSERT_FATAL(l3_offset != ODP_PACKET_OFFSET_INVALID); + + if (odp_packet_has_ipv4(pkt)) { + odph_ipv4hdr_t ip; + + rc = odp_packet_copy_to_mem(pkt, l3_offset, sizeof(ip), &ip); + CU_ASSERT_FATAL(rc == 0); + len = odp_be_to_cpu_16(ip.tot_len); + } else if (odp_packet_has_ipv6(pkt)) { + odph_ipv6hdr_t ip; + + rc = odp_packet_copy_to_mem(pkt, l3_offset, sizeof(ip), &ip); + CU_ASSERT_FATAL(rc == 0); + len = sizeof(ip) + odp_be_to_cpu_16(ip.payload_len); + } else { + CU_FAIL_FATAL("Unexcpected packet type"); + } + + return l3_offset + len - sizeof(cls_test_packet_t); +} + int cls_pkt_set_seq(odp_packet_t pkt) { - static uint32_t seq; cls_test_packet_t data; + static uint32_t seq; uint32_t offset; - odph_ipv4hdr_t *ip; - odph_tcphdr_t *tcp; - odph_udphdr_t *udp; - uint16_t port = 0; - uint32_t hlen = 0; int status; data.magic = DATA_MAGIC; data.seq = ++seq; - ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); - offset = odp_packet_l4_offset(pkt); - CU_ASSERT_FATAL(offset != ODP_PACKET_OFFSET_INVALID); - - if (ip->proto == ODPH_IPPROTO_IGMP) { - status = odp_packet_copy_from_mem(pkt, offset + ODP_IGMP_HLEN, - sizeof(data), &data); - } else if (ip->proto == ODPH_IPPROTO_ICMPV4) { - status = odp_packet_copy_from_mem(pkt, offset + ODPH_ICMPHDR_LEN, - sizeof(data), &data); - } else if (ip->proto == ODPH_IPPROTO_SCTP) { - /* Create some invalid SCTP packet for testing under the assumption that - * no implementation really cares - */ - status = odp_packet_copy_from_mem(pkt, offset + ODPH_SCTPHDR_LEN, - sizeof(data), &data); - } else if (ip->proto == ODPH_IPPROTO_UDP) { - udp = (odph_udphdr_t *)odp_packet_l4_ptr(pkt, NULL); - port = odp_be_to_cpu_16(udp->dst_port); - if (port == ODP_GTPU_UDP_PORT) { - hlen = offset + ODPH_UDPHDR_LEN + ODP_GTP_HLEN; - status = odp_packet_copy_from_mem(pkt, hlen, - sizeof(data), &data); - } else { - status = odp_packet_copy_from_mem(pkt, offset + ODPH_UDPHDR_LEN, - sizeof(data), &data); - } - } else { - tcp = (odph_tcphdr_t *)odp_packet_l4_ptr(pkt, NULL); - status = odp_packet_copy_from_mem(pkt, offset + tcp->hl * 4, - sizeof(data), &data); - } + offset = seqno_offset(pkt); + + status = odp_packet_copy_from_mem(pkt, offset, sizeof(data), &data); return status; } uint32_t cls_pkt_get_seq(odp_packet_t pkt) { - uint32_t offset; cls_test_packet_t data; - odph_ipv4hdr_t *ip; - odph_tcphdr_t *tcp; - odph_udphdr_t *udp; - uint32_t hlen = 0; - uint16_t port = 0; - - ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL); - offset = odp_packet_l4_offset(pkt); - - if (offset == ODP_PACKET_OFFSET_INVALID || ip == NULL) - return TEST_SEQ_INVALID; - - if (ip->proto == ODPH_IPPROTO_IGMP) { - odp_packet_copy_to_mem(pkt, offset + ODP_IGMP_HLEN, - sizeof(data), &data); - - } else if (ip->proto == ODPH_IPPROTO_ICMPV4) { - odp_packet_copy_to_mem(pkt, offset + ODPH_ICMPHDR_LEN, - sizeof(data), &data); - } else if (ip->proto == ODPH_IPPROTO_SCTP) { - odp_packet_copy_to_mem(pkt, offset + ODPH_SCTPHDR_LEN, - sizeof(data), &data); - } else if (ip->proto == ODPH_IPPROTO_UDP) { - udp = (odph_udphdr_t *)odp_packet_l4_ptr(pkt, NULL); - port = odp_be_to_cpu_16(udp->dst_port); - if (port == ODP_GTPU_UDP_PORT) { - hlen = offset + ODPH_UDPHDR_LEN + ODP_GTP_HLEN; - odp_packet_copy_to_mem(pkt, hlen, sizeof(data), &data); - } else { - odp_packet_copy_to_mem(pkt, offset + ODPH_UDPHDR_LEN, - sizeof(data), &data); - } - } else { - tcp = (odph_tcphdr_t *)odp_packet_l4_ptr(pkt, NULL); - odp_packet_copy_to_mem(pkt, offset + tcp->hl * 4, - sizeof(data), &data); - } + uint32_t offset; + int rc; + + offset = seqno_offset(pkt); + + rc = odp_packet_copy_to_mem(pkt, offset, sizeof(data), &data); + CU_ASSERT_FATAL(rc == 0); if (data.magic == DATA_MAGIC) return data.seq; -- cgit v1.2.3 From d1231c3e747d73b13515bb18948c39db7da8b6bb Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Mon, 12 Oct 2020 13:53:18 +0300 Subject: api: pktio: enable setting input and output maximum frame lengths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new function odp_pktio_maxlen_set() for setting the maximum frame lengths for packet input and output. Add the corresponding capabilities to odp_pktio_capability_t. Signed-off-by: Matias Elo Reviewed-by: Nithin Dabilpuram Reviewed-by: Jere Leppänen Reviewed-by: Petri Savolainen --- include/odp/api/spec/packet_io.h | 49 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/include/odp/api/spec/packet_io.h b/include/odp/api/spec/packet_io.h index 0b6c95033..af3c72dde 100644 --- a/include/odp/api/spec/packet_io.h +++ b/include/odp/api/spec/packet_io.h @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2020, Nokia + * Copyright (c) 2020-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -633,6 +633,8 @@ typedef union odp_pktio_set_op_t { uint32_t mac_addr : 1; /** Per port header offset(skip)set */ uint32_t skip_offset : 1; + /** Maximum frame length */ + uint32_t maxlen : 1; } op; /** All bits of the bit field structure. * This field can be used to set/clear all flags, or bitwise @@ -824,6 +826,25 @@ typedef struct odp_pktio_capability_t { /** LSO capabilities */ odp_lso_capability_t lso; + /** Supported frame lengths for odp_pktio_maxlen_set() + * + * A frame length value of zero indicates an unsupported operation. */ + struct { + /** Equal maximum frame length for both packet input and output + * + * When set, the same maximum frame length value has to be used + * for both input and output directions. */ + odp_bool_t equal; + /** Minimum valid value for 'maxlen_input' */ + uint32_t min_input; + /** Maximum valid value for 'maxlen_input' */ + uint32_t max_input; + /** Minimum valid value for 'maxlen_output' */ + uint32_t min_output; + /** Maximum valid value for 'maxlen_output' */ + uint32_t max_output; + } maxlen; + } odp_pktio_capability_t; /** @@ -1429,6 +1450,32 @@ uint32_t odp_pktin_maxlen(odp_pktio_t pktio); */ uint32_t odp_pktout_maxlen(odp_pktio_t pktio); +/** + * Set maximum frame lengths + * + * Set the maximum frame lengths in bytes that the packet IO interface can + * receive and transmit. For Ethernet, the frame length bytes start with MAC + * addresses and continue to the end of the payload. So, Ethernet checksum, + * interpacket gap, and preamble bytes are excluded from the lengths. + * + * Use odp_pktio_capability() to query interface capabilities. If setting + * maximum frame length is only supported in input or output direction, the + * parameter for the unsupported direction has to be set to zero. When + * 'equal' flag in odp_pktio_capability_t::maxlen is set, the same maximum + * frame length value has to be used for both input and output directions. + * + * @param pktio Packet IO handle + * @param maxlen_input Maximum frame length at packet input + * @param maxlen_output Maximum frame length at packet output + * + * @retval 0 on success + * @retval <0 on failure + * + * @see odp_pktin_maxlen(), odp_pktout_maxlen() + */ +int odp_pktio_maxlen_set(odp_pktio_t pktio, uint32_t maxlen_input, + uint32_t maxlen_output); + /** * Get the default MAC address of a packet IO interface. * -- cgit v1.2.3 From a167edffba725e80fee6169eca6d3d458cb9bb90 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 14 Oct 2020 10:28:18 +0300 Subject: linux-gen: pktio: rename pktio_if_ops_t mtu_get to maxlen_get Rename pktio_if_ops_t.mtu_get to maxlen_get to make naming consistent with the API functions. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/include/odp_packet_io_internal.h | 2 +- platform/linux-generic/odp_packet_io.c | 14 +++++++------- platform/linux-generic/pktio/dpdk.c | 2 +- platform/linux-generic/pktio/ipc.c | 2 +- platform/linux-generic/pktio/loop.c | 2 +- platform/linux-generic/pktio/netmap.c | 2 +- platform/linux-generic/pktio/null.c | 2 +- platform/linux-generic/pktio/pcap.c | 2 +- platform/linux-generic/pktio/socket.c | 2 +- platform/linux-generic/pktio/socket_mmap.c | 2 +- platform/linux-generic/pktio/tap.c | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index afd36681a..e184fabbc 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -204,7 +204,7 @@ typedef struct pktio_if_ops { int (*fd_set)(pktio_entry_t *entry, int index, fd_set *readfds); int (*send)(pktio_entry_t *entry, int index, const odp_packet_t packets[], int num); - uint32_t (*mtu_get)(pktio_entry_t *pktio_entry); + uint32_t (*maxlen_get)(pktio_entry_t *pktio_entry); int (*promisc_mode_set)(pktio_entry_t *pktio_entry, int enable); int (*promisc_mode_get)(pktio_entry_t *pktio_entry); int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr); diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index 23c92931d..b9f7acb8f 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -1246,7 +1246,7 @@ void _odp_sched_cb_pktio_stop_finalize(int pktio_index) unlock_entry(entry); } -static inline uint32_t pktio_mtu(odp_pktio_t hdl) +static inline uint32_t pktio_maxlen(odp_pktio_t hdl) { pktio_entry_t *entry; uint32_t ret = 0; @@ -1265,8 +1265,8 @@ static inline uint32_t pktio_mtu(odp_pktio_t hdl) return 0; } - if (entry->s.ops->mtu_get) - ret = entry->s.ops->mtu_get(entry); + if (entry->s.ops->maxlen_get) + ret = entry->s.ops->maxlen_get(entry); unlock_entry(entry); return ret; @@ -1274,17 +1274,17 @@ static inline uint32_t pktio_mtu(odp_pktio_t hdl) uint32_t ODP_DEPRECATE(odp_pktio_mtu)(odp_pktio_t pktio) { - return pktio_mtu(pktio); + return pktio_maxlen(pktio); } uint32_t odp_pktin_maxlen(odp_pktio_t pktio) { - return pktio_mtu(pktio); + return pktio_maxlen(pktio); } uint32_t odp_pktout_maxlen(odp_pktio_t pktio) { - return pktio_mtu(pktio); + return pktio_maxlen(pktio); } int odp_pktio_promisc_mode_set(odp_pktio_t hdl, odp_bool_t enable) @@ -1726,7 +1726,7 @@ int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa) ret = single_capability(capa); if (ret == 0) { - uint32_t mtu = pktio_mtu(pktio); + uint32_t mtu = pktio_maxlen(pktio); if (mtu == 0) { ODP_DBG("MTU query failed: %s\n", entry->s.name); diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index f65bee7a1..252437000 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -2185,7 +2185,7 @@ const pktio_if_ops_t dpdk_pktio_ops = { .send = dpdk_send, .link_status = dpdk_link_status, .link_info = dpdk_link_info, - .mtu_get = dpdk_frame_maxlen, + .maxlen_get = dpdk_frame_maxlen, .promisc_mode_set = dpdk_promisc_mode_set, .promisc_mode_get = dpdk_promisc_mode_get, .mac_get = dpdk_mac_addr_get, diff --git a/platform/linux-generic/pktio/ipc.c b/platform/linux-generic/pktio/ipc.c index cc2b7db61..845fd821d 100644 --- a/platform/linux-generic/pktio/ipc.c +++ b/platform/linux-generic/pktio/ipc.c @@ -978,7 +978,7 @@ const pktio_if_ops_t _odp_ipc_pktio_ops = { .stop = ipc_stop, .link_status = ipc_link_status, .link_info = ipc_link_info, - .mtu_get = ipc_mtu_get, + .maxlen_get = ipc_mtu_get, .promisc_mode_set = NULL, .promisc_mode_get = NULL, .mac_get = ipc_mac_addr_get, diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index cc4cb1751..940dd3ad3 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -487,7 +487,7 @@ const pktio_if_ops_t _odp_loopback_pktio_ops = { .stats_reset = loopback_stats_reset, .recv = loopback_recv, .send = loopback_send, - .mtu_get = loopback_mtu_get, + .maxlen_get = loopback_mtu_get, .promisc_mode_set = loopback_promisc_mode_set, .promisc_mode_get = loopback_promisc_mode_get, .mac_get = loopback_mac_addr_get, diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c index 0e01a9a1f..30fc532fc 100644 --- a/platform/linux-generic/pktio/netmap.c +++ b/platform/linux-generic/pktio/netmap.c @@ -1261,7 +1261,7 @@ const pktio_if_ops_t netmap_pktio_ops = { .link_info = netmap_link_info, .stats = netmap_stats, .stats_reset = netmap_stats_reset, - .mtu_get = netmap_mtu_get, + .maxlen_get = netmap_mtu_get, .promisc_mode_set = netmap_promisc_mode_set, .promisc_mode_get = netmap_promisc_mode_get, .mac_get = netmap_mac_addr_get, diff --git a/platform/linux-generic/pktio/null.c b/platform/linux-generic/pktio/null.c index be7ba4991..cbcde323c 100644 --- a/platform/linux-generic/pktio/null.c +++ b/platform/linux-generic/pktio/null.c @@ -207,7 +207,7 @@ const pktio_if_ops_t _odp_null_pktio_ops = { .recv_mq_tmo = null_recv_mq_tmo, .fd_set = null_fd_set, .send = null_send, - .mtu_get = null_mtu_get, + .maxlen_get = null_mtu_get, .promisc_mode_set = null_promisc_mode_set, .promisc_mode_get = null_promisc_mode_get, .mac_get = null_mac_addr_get, diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c index 4ca0064a3..f80242a70 100644 --- a/platform/linux-generic/pktio/pcap.c +++ b/platform/linux-generic/pktio/pcap.c @@ -508,7 +508,7 @@ const pktio_if_ops_t _odp_pcap_pktio_ops = { .stats_reset = pcapif_stats_reset, .recv = pcapif_recv_pkt, .send = pcapif_send_pkt, - .mtu_get = pcapif_mtu_get, + .maxlen_get = pcapif_mtu_get, .promisc_mode_set = pcapif_promisc_mode_set, .promisc_mode_get = pcapif_promisc_mode_get, .mac_get = pcapif_mac_addr_get, diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c index 9d8c5b0bc..62fa96742 100644 --- a/platform/linux-generic/pktio/socket.c +++ b/platform/linux-generic/pktio/socket.c @@ -577,7 +577,7 @@ const pktio_if_ops_t _odp_sock_mmsg_pktio_ops = { .recv_mq_tmo = sock_recv_mq_tmo, .fd_set = sock_fd_set, .send = sock_mmsg_send, - .mtu_get = sock_mtu_get, + .maxlen_get = sock_mtu_get, .promisc_mode_set = sock_promisc_mode_set, .promisc_mode_get = sock_promisc_mode_get, .mac_get = sock_mac_addr_get, diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c index 9fc992d78..5d827fd10 100644 --- a/platform/linux-generic/pktio/socket_mmap.c +++ b/platform/linux-generic/pktio/socket_mmap.c @@ -895,7 +895,7 @@ const pktio_if_ops_t _odp_sock_mmap_pktio_ops = { .recv_mq_tmo = sock_mmap_recv_mq_tmo, .send = sock_mmap_send, .fd_set = sock_mmap_fd_set, - .mtu_get = sock_mmap_mtu_get, + .maxlen_get = sock_mmap_mtu_get, .promisc_mode_set = sock_mmap_promisc_mode_set, .promisc_mode_get = sock_mmap_promisc_mode_get, .mac_get = sock_mmap_mac_addr_get, diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c index 42693bd6d..34c30bbac 100644 --- a/platform/linux-generic/pktio/tap.c +++ b/platform/linux-generic/pktio/tap.c @@ -509,7 +509,7 @@ const pktio_if_ops_t _odp_tap_pktio_ops = { .stop = tap_pktio_stop, .recv = tap_pktio_recv, .send = tap_pktio_send, - .mtu_get = tap_mtu_get, + .maxlen_get = tap_mtu_get, .promisc_mode_set = tap_promisc_mode_set, .promisc_mode_get = tap_promisc_mode_get, .mac_get = tap_mac_addr_get, -- cgit v1.2.3 From 92dd2794c6854d572dfd7cc760b8e09f4a3ef0e9 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 14 Oct 2020 10:32:06 +0300 Subject: linux-gen: pktio: implement odp_pktio_maxlen_set() Add implementation for the new odp_pktio_maxlen_set() function. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- .../linux-generic/include/odp_packet_io_internal.h | 2 + platform/linux-generic/odp_packet_io.c | 68 +++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index e184fabbc..c6b916240 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -205,6 +205,8 @@ typedef struct pktio_if_ops { int (*send)(pktio_entry_t *entry, int index, const odp_packet_t packets[], int num); uint32_t (*maxlen_get)(pktio_entry_t *pktio_entry); + int (*maxlen_set)(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output); int (*promisc_mode_set)(pktio_entry_t *pktio_entry, int enable); int (*promisc_mode_get)(pktio_entry_t *pktio_entry); int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr); diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index b9f7acb8f..846db868c 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019-2020, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -1287,6 +1287,72 @@ uint32_t odp_pktout_maxlen(odp_pktio_t pktio) return pktio_maxlen(pktio); } +int odp_pktio_maxlen_set(odp_pktio_t hdl, uint32_t maxlen_input, + uint32_t maxlen_output) +{ + odp_pktio_capability_t capa; + pktio_entry_t *entry; + int ret = 0; + + entry = get_pktio_entry(hdl); + if (entry == NULL) { + ODP_ERR("Pktio entry %d does not exist\n", hdl); + return -1; + } + + ret = odp_pktio_capability(hdl, &capa); + if (ret) { + ODP_ERR("Reading pktio capability failed\n"); + goto fail; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + ODP_ERR("Pktio already freed\n"); + ret = -1; + goto fail; + } + if (entry->s.state == PKTIO_STATE_STARTED) { + ODP_ERR("Pktio not stopped\n"); + ret = -1; + goto fail; + } + + if (capa.set_op.op.maxlen == 0) { + ODP_ERR("Setting maximum frame length not supported\n"); + ret = -1; + goto fail; + } + + if (capa.maxlen.equal && (maxlen_input != maxlen_output)) { + ODP_ERR("Max input and output lengths don't match\n"); + ret = -1; + goto fail; + } + + if (maxlen_input < capa.maxlen.min_input || + maxlen_input > capa.maxlen.max_input) { + ODP_ERR("Invalid max input length value: %" PRIu32 "\n", maxlen_input); + ret = -1; + goto fail; + } + + if (maxlen_output < capa.maxlen.min_output || + maxlen_output > capa.maxlen.max_output) { + ODP_ERR("Invalid max output length value: %" PRIu32 "\n", maxlen_output); + ret = -1; + goto fail; + } + + if (entry->s.ops->maxlen_set) + ret = entry->s.ops->maxlen_set(entry, maxlen_input, maxlen_output); + +fail: + unlock_entry(entry); + return ret; +} + int odp_pktio_promisc_mode_set(odp_pktio_t hdl, odp_bool_t enable) { pktio_entry_t *entry; -- cgit v1.2.3 From fc21f753a6c02bcc0ad018621eb900b0057bbe96 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 14 Oct 2020 10:46:09 +0300 Subject: linux-gen: socket: implement odp_pktio_maxlen_set() Implementation of odp_pktio_maxlen_set() for socket pktio. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/include/odp_socket_common.h | 9 ++++--- platform/linux-generic/pktio/socket.c | 31 +++++++++++++++++++++- platform/linux-generic/pktio/socket_common.c | 7 ++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/platform/linux-generic/include/odp_socket_common.h b/platform/linux-generic/include/odp_socket_common.h index 02cebdf85..f48dabc3b 100644 --- a/platform/linux-generic/include/odp_socket_common.h +++ b/platform/linux-generic/include/odp_socket_common.h @@ -13,20 +13,23 @@ extern "C" { #endif #include +#include #include -#include + +#define _ODP_SOCKET_MTU_MIN (68 + _ODP_ETHHDR_LEN) +#define _ODP_SOCKET_MTU_MAX (9000 + _ODP_ETHHDR_LEN) static inline void ethaddr_copy(unsigned char mac_dst[], unsigned char mac_src[]) { - memcpy(mac_dst, mac_src, ETH_ALEN); + memcpy(mac_dst, mac_src, _ODP_ETHADDR_LEN); } static inline int ethaddrs_equal(unsigned char mac_a[], unsigned char mac_b[]) { - return !memcmp(mac_a, mac_b, ETH_ALEN); + return !memcmp(mac_a, mac_b, _ODP_ETHADDR_LEN); } /** diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c index 62fa96742..29b6c9af6 100644 --- a/platform/linux-generic/pktio/socket.c +++ b/platform/linux-generic/pktio/socket.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2013-2020, Nokia Solutions and Networks + * Copyright (c) 2013-2021, Nokia Solutions and Networks * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -35,6 +35,7 @@ typedef struct { int sockfd; /**< socket descriptor */ odp_pool_t pool; /**< pool to alloc packets from */ uint32_t mtu; /**< maximum transmission unit */ + uint32_t mtu_max; /**< maximum supported MTU value */ unsigned char if_mac[ETH_ALEN]; /**< IF eth mac addr */ } pkt_sock_t; @@ -144,6 +145,9 @@ static int sock_setup_pkt(pktio_entry_t *pktio_entry, const char *netdev, pkt_sock->mtu = _odp_mtu_get_fd(sockfd, netdev); if (!pkt_sock->mtu) goto error; + pkt_sock->mtu_max = _ODP_SOCKET_MTU_MAX; + if (pkt_sock->mtu > pkt_sock->mtu_max) + pkt_sock->mtu_max = pkt_sock->mtu; /* bind socket to if */ memset(&sa_ll, 0, sizeof(sa_ll)); @@ -476,6 +480,21 @@ static uint32_t sock_mtu_get(pktio_entry_t *pktio_entry) return pkt_priv(pktio_entry)->mtu; } +static int sock_mtu_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output ODP_UNUSED) +{ + pkt_sock_t *pkt_sock = pkt_priv(pktio_entry); + int ret; + + ret = _odp_mtu_set_fd(pkt_sock->sockfd, pktio_entry->s.name, maxlen_input); + if (ret) + return ret; + + pkt_sock->mtu = maxlen_input; + + return 0; +} + static int sock_mac_addr_get(pktio_entry_t *pktio_entry, void *mac_addr) { @@ -510,11 +529,20 @@ static int sock_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *inf static int sock_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { + pkt_sock_t *pkt_sock = pkt_priv(pktio_entry); + memset(capa, 0, sizeof(odp_pktio_capability_t)); capa->max_input_queues = 1; capa->max_output_queues = 1; capa->set_op.op.promisc_mode = 1; + capa->set_op.op.maxlen = 1; + + capa->maxlen.equal = true; + capa->maxlen.min_input = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_input = pkt_sock->mtu_max; + capa->maxlen.min_output = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_output = pkt_sock->mtu_max; odp_pktio_config_init(&capa->config); capa->config.pktin.bit.ts_all = 1; @@ -578,6 +606,7 @@ const pktio_if_ops_t _odp_sock_mmsg_pktio_ops = { .fd_set = sock_fd_set, .send = sock_mmsg_send, .maxlen_get = sock_mtu_get, + .maxlen_set = sock_mtu_set, .promisc_mode_set = sock_promisc_mode_set, .promisc_mode_get = sock_promisc_mode_get, .mac_get = sock_mac_addr_get, diff --git a/platform/linux-generic/pktio/socket_common.c b/platform/linux-generic/pktio/socket_common.c index b9bd97411..473b58a6c 100644 --- a/platform/linux-generic/pktio/socket_common.c +++ b/platform/linux-generic/pktio/socket_common.c @@ -82,7 +82,7 @@ uint32_t _odp_mtu_get_fd(int fd, const char *name) ret = ioctl(fd, SIOCGIFMTU, &ifr); if (ret < 0) { __odp_errno = errno; - ODP_DBG("ioctl(SIOCGIFMTU): %s: \"%s\".\n", strerror(errno), + ODP_ERR("ioctl(SIOCGIFMTU): %s: \"%s\".\n", strerror(errno), ifr.ifr_name); return 0; } @@ -90,6 +90,7 @@ uint32_t _odp_mtu_get_fd(int fd, const char *name) } /* + * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_NETMAP: */ int _odp_mtu_set_fd(int fd, const char *name, int mtu) @@ -98,12 +99,12 @@ int _odp_mtu_set_fd(int fd, const char *name, int mtu) int ret; snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name); - ifr.ifr_mtu = mtu; + ifr.ifr_mtu = mtu - _ODP_ETHHDR_LEN; ret = ioctl(fd, SIOCSIFMTU, &ifr); if (ret < 0) { __odp_errno = errno; - ODP_DBG("ioctl(SIOCSIFMTU): %s: \"%s\".\n", strerror(errno), + ODP_ERR("ioctl(SIOCSIFMTU): %s: \"%s\".\n", strerror(errno), ifr.ifr_name); return -1; } -- cgit v1.2.3 From c6041fc42d751e4049a4e3b6870914473517b416 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 13 Jan 2021 15:46:43 +0200 Subject: linux-gen: loop: implement odp_pktio_maxlen_set() Implementation of odp_pktio_maxlen_set() for loop pktio. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/loop.c | 44 +++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index 940dd3ad3..1d5751eb8 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2013-2020, Nokia Solutions and Networks + * Copyright (c) 2013-2021, Nokia Solutions and Networks * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -25,14 +25,18 @@ #include #include #include +#include #include #define MAX_LOOP 16 -#define LOOP_MTU (64 * 1024) + +#define LOOP_MTU_MIN 68 +#define LOOP_MTU_MAX UINT16_MAX typedef struct { odp_queue_t loopq; /**< loopback queue for "loop" device */ odp_bool_t promisc; /**< promiscuous mode state */ + uint16_t mtu; /**< link MTU */ uint8_t idx; /**< index of "loop" device */ } pkt_loop_t; @@ -53,6 +57,7 @@ static int loopback_init_capability(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) { + pkt_loop_t *pkt_loop = pkt_priv(pktio_entry); long idx; char loopq_name[ODP_QUEUE_NAME_LEN]; @@ -70,11 +75,11 @@ static int loopback_open(odp_pktio_t id, pktio_entry_t *pktio_entry, snprintf(loopq_name, sizeof(loopq_name), "%" PRIu64 "-pktio_loopq", odp_pktio_to_u64(id)); - pkt_priv(pktio_entry)->loopq = - odp_queue_create(loopq_name, NULL); - pkt_priv(pktio_entry)->idx = idx; + pkt_loop->idx = idx; + pkt_loop->mtu = LOOP_MTU_MAX; + pkt_loop->loopq = odp_queue_create(loopq_name, NULL); - if (pkt_priv(pktio_entry)->loopq == ODP_QUEUE_INVALID) + if (pkt_loop->loopq == ODP_QUEUE_INVALID) return -1; loopback_stats_reset(pktio_entry); @@ -284,6 +289,7 @@ static inline void loopback_fix_checksums(odp_packet_t pkt, static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED, const odp_packet_t pkt_tbl[], int num) { + pkt_loop_t *pkt_loop = pkt_priv(pktio_entry); odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX]; odp_queue_t queue; int i; @@ -303,7 +309,7 @@ static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED, for (i = 0; i < num; ++i) { uint32_t pkt_len = odp_packet_len(pkt_tbl[i]); - if (pkt_len > LOOP_MTU) { + if (odp_unlikely(pkt_len > pkt_loop->mtu)) { if (nb_tx == 0) { __odp_errno = EMSGSIZE; return -1; @@ -361,9 +367,21 @@ static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED, return ret; } -static uint32_t loopback_mtu_get(pktio_entry_t *pktio_entry ODP_UNUSED) +static uint32_t loopback_mtu_get(pktio_entry_t *pktio_entry) { - return LOOP_MTU; + pkt_loop_t *pkt_loop = pkt_priv(pktio_entry); + + return pkt_loop->mtu; +} + +static int loopback_mtu_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output ODP_UNUSED) +{ + pkt_loop_t *pkt_loop = pkt_priv(pktio_entry); + + pkt_loop->mtu = maxlen_input; + + return 0; } static int loopback_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED, @@ -404,6 +422,13 @@ static int loopback_init_capability(pktio_entry_t *pktio_entry) capa->max_input_queues = 1; capa->max_output_queues = 1; capa->set_op.op.promisc_mode = 1; + capa->set_op.op.maxlen = 1; + + capa->maxlen.equal = true; + capa->maxlen.min_input = LOOP_MTU_MIN; + capa->maxlen.max_input = LOOP_MTU_MAX; + capa->maxlen.min_output = LOOP_MTU_MIN; + capa->maxlen.max_output = LOOP_MTU_MAX; odp_pktio_config_init(&capa->config); capa->config.pktin.bit.ts_all = 1; @@ -488,6 +513,7 @@ const pktio_if_ops_t _odp_loopback_pktio_ops = { .recv = loopback_recv, .send = loopback_send, .maxlen_get = loopback_mtu_get, + .maxlen_set = loopback_mtu_set, .promisc_mode_set = loopback_promisc_mode_set, .promisc_mode_get = loopback_promisc_mode_get, .mac_get = loopback_mac_addr_get, -- cgit v1.2.3 From 306153903d509175aee59b2c0fbc1d807f65ec06 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 14 Jan 2021 16:13:14 +0200 Subject: linux-gen: tap: implement odp_pktio_maxlen_set() Implementation of odp_pktio_maxlen_set() for TAP pktio. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/socket_common.c | 2 ++ platform/linux-generic/pktio/tap.c | 46 +++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/platform/linux-generic/pktio/socket_common.c b/platform/linux-generic/pktio/socket_common.c index 473b58a6c..d8b01050e 100644 --- a/platform/linux-generic/pktio/socket_common.c +++ b/platform/linux-generic/pktio/socket_common.c @@ -72,6 +72,7 @@ int _odp_mac_addr_get_fd(int fd, const char *name, unsigned char mac_dst[]) * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: * ODP_PACKET_NETMAP: + * ODP_PACKET_TAP: */ uint32_t _odp_mtu_get_fd(int fd, const char *name) { @@ -92,6 +93,7 @@ uint32_t _odp_mtu_get_fd(int fd, const char *name) /* * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_NETMAP: + * ODP_PACKET_TAP: */ int _odp_mtu_set_fd(int fd, const char *name, int mtu) { diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c index 34c30bbac..cb85e9afd 100644 --- a/platform/linux-generic/pktio/tap.c +++ b/platform/linux-generic/pktio/tap.c @@ -1,4 +1,5 @@ /* Copyright (c) 2015, Ilya Maximets + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -47,12 +48,11 @@ #include #include -#define BUF_SIZE 65536 - typedef struct { int fd; /**< file descriptor for tap interface*/ int skfd; /**< socket descriptor */ uint32_t mtu; /**< cached mtu */ + uint32_t mtu_max; /**< maximum supported MTU value */ unsigned char if_mac[ETH_ALEN]; /**< MAC address of pktio side (not a MAC address of kernel interface)*/ odp_pool_t pool; /**< pool to alloc packets from */ @@ -173,6 +173,9 @@ static int tap_pktio_open(odp_pktio_t id ODP_UNUSED, ODP_ERR("_odp_mtu_get_fd failed: %s\n", strerror(errno)); goto sock_err; } + tap->mtu_max = _ODP_SOCKET_MTU_MAX; + if (mtu > tap->mtu_max) + tap->mtu_max = mtu; tap->fd = fd; tap->skfd = skfd; @@ -318,10 +321,11 @@ static odp_packet_t pack_odp_pkt(pktio_entry_t *pktio_entry, const void *data, static int tap_pktio_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED, odp_packet_t pkts[], int num) { + pkt_tap_t *tap = pkt_priv(pktio_entry); ssize_t retval; int i; - uint8_t buf[BUF_SIZE]; - pkt_tap_t *tap = pkt_priv(pktio_entry); + uint32_t mtu = tap->mtu; + uint8_t buf[mtu]; odp_time_t ts_val; odp_time_t *ts = NULL; @@ -333,7 +337,7 @@ static int tap_pktio_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED, for (i = 0; i < num; i++) { do { - retval = read(tap->fd, buf, BUF_SIZE); + retval = read(tap->fd, buf, mtu); } while (retval < 0 && errno == EINTR); if (ts != NULL) @@ -357,17 +361,18 @@ static int tap_pktio_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED, static int tap_pktio_send_lockless(pktio_entry_t *pktio_entry, const odp_packet_t pkts[], int num) { + pkt_tap_t *tap = pkt_priv(pktio_entry); ssize_t retval; int i, n; uint32_t pkt_len; + uint32_t mtu = tap->mtu; uint8_t tx_ts_enabled = _odp_pktio_tx_ts_enabled(pktio_entry); - uint8_t buf[BUF_SIZE]; - pkt_tap_t *tap = pkt_priv(pktio_entry); + uint8_t buf[mtu]; for (i = 0; i < num; i++) { pkt_len = odp_packet_len(pkts[i]); - if (pkt_len > tap->mtu) { + if (odp_unlikely(pkt_len > mtu)) { if (i == 0) { __odp_errno = EMSGSIZE; return -1; @@ -438,6 +443,21 @@ static uint32_t tap_mtu_get(pktio_entry_t *pktio_entry) return ret; } +static int tap_mtu_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output ODP_UNUSED) +{ + pkt_tap_t *tap = pkt_priv(pktio_entry); + int ret; + + ret = _odp_mtu_set_fd(tap->skfd, pktio_entry->s.name + 4, maxlen_input); + if (ret) + return ret; + + tap->mtu = maxlen_input; + + return 0; +} + static int tap_promisc_mode_set(pktio_entry_t *pktio_entry, odp_bool_t enable) { @@ -481,12 +501,21 @@ static int tap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info static int tap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { + pkt_tap_t *tap = pkt_priv(pktio_entry); + memset(capa, 0, sizeof(odp_pktio_capability_t)); capa->max_input_queues = 1; capa->max_output_queues = 1; capa->set_op.op.promisc_mode = 1; capa->set_op.op.mac_addr = 1; + capa->set_op.op.maxlen = 1; + + capa->maxlen.equal = true; + capa->maxlen.min_input = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_input = tap->mtu_max; + capa->maxlen.min_output = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_output = tap->mtu_max; odp_pktio_config_init(&capa->config); capa->config.pktin.bit.ts_all = 1; @@ -510,6 +539,7 @@ const pktio_if_ops_t _odp_tap_pktio_ops = { .recv = tap_pktio_recv, .send = tap_pktio_send, .maxlen_get = tap_mtu_get, + .maxlen_set = tap_mtu_set, .promisc_mode_set = tap_promisc_mode_set, .promisc_mode_get = tap_promisc_mode_get, .mac_get = tap_mac_addr_get, -- cgit v1.2.3 From 0870f3393380c4b76afc2c500db9f82162e5cd11 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 15 Jan 2021 09:06:12 +0200 Subject: linux-gen: socket_mmap: implement odp_pktio_maxlen_set() Implementation of odp_pktio_maxlen_set() for socket_mmap pktio. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/socket_common.c | 1 + platform/linux-generic/pktio/socket_mmap.c | 33 ++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/platform/linux-generic/pktio/socket_common.c b/platform/linux-generic/pktio/socket_common.c index d8b01050e..88c1471b0 100644 --- a/platform/linux-generic/pktio/socket_common.c +++ b/platform/linux-generic/pktio/socket_common.c @@ -91,6 +91,7 @@ uint32_t _odp_mtu_get_fd(int fd, const char *name) } /* + * ODP_PACKET_SOCKET_MMAP: * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_NETMAP: * ODP_PACKET_TAP: diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c index 5d827fd10..05d0d8254 100644 --- a/platform/linux-generic/pktio/socket_mmap.c +++ b/platform/linux-generic/pktio/socket_mmap.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2013-2020, Nokia Solutions and Networks + * Copyright (c) 2013-2021, Nokia Solutions and Networks * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -84,6 +84,7 @@ typedef struct { int sockfd ODP_ALIGNED_CACHE; odp_pool_t pool; int mtu; /**< maximum transmission unit */ + uint32_t mtu_max; /**< maximum supported MTU value */ size_t frame_offset; /**< frame start offset from start of pkt buf */ uint8_t *mmap_base; unsigned int mmap_len; @@ -413,7 +414,7 @@ static int mmap_setup_ring(pkt_sock_mmap_t *pkt_sock, struct ring *ring, uint32_t ring_size; int flags; int sock = pkt_sock->sockfd; - int mtu = pkt_sock->mtu; + int mtu = pkt_sock->mtu_max; int ret = 0; ring->sock = sock; @@ -614,6 +615,9 @@ static int sock_mmap_open(odp_pktio_t id ODP_UNUSED, pkt_sock->mtu = _odp_mtu_get_fd(pkt_sock->sockfd, netdev); if (!pkt_sock->mtu) goto error; + pkt_sock->mtu_max = _ODP_SOCKET_MTU_MAX; + if (pkt_sock->mtu > _ODP_SOCKET_MTU_MAX) + pkt_sock->mtu_max = pkt_sock->mtu; ODP_DBG("MTU size: %i\n", pkt_sock->mtu); @@ -792,6 +796,21 @@ static uint32_t sock_mmap_mtu_get(pktio_entry_t *pktio_entry) pktio_entry->s.name); } +static int sock_mmap_mtu_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output ODP_UNUSED) +{ + pkt_sock_mmap_t *pkt_sock = pkt_priv(pktio_entry); + int ret; + + ret = _odp_mtu_set_fd(pkt_sock->sockfd, pktio_entry->s.name, maxlen_input); + if (ret) + return ret; + + pkt_sock->mtu = maxlen_input; + + return 0; +} + static int sock_mmap_mac_addr_get(pktio_entry_t *pktio_entry, void *mac_addr) { memcpy(mac_addr, pkt_priv(pktio_entry)->if_mac, ETH_ALEN); @@ -825,11 +844,20 @@ static int sock_mmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t static int sock_mmap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { + pkt_sock_mmap_t *const pkt_sock = pkt_priv(pktio_entry); + memset(capa, 0, sizeof(odp_pktio_capability_t)); capa->max_input_queues = 1; capa->max_output_queues = 1; capa->set_op.op.promisc_mode = 1; + capa->set_op.op.maxlen = 1; + + capa->maxlen.equal = true; + capa->maxlen.min_input = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_input = pkt_sock->mtu_max; + capa->maxlen.min_output = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_output = pkt_sock->mtu_max; odp_pktio_config_init(&capa->config); capa->config.pktin.bit.ts_all = 1; @@ -896,6 +924,7 @@ const pktio_if_ops_t _odp_sock_mmap_pktio_ops = { .send = sock_mmap_send, .fd_set = sock_mmap_fd_set, .maxlen_get = sock_mmap_mtu_get, + .maxlen_set = sock_mmap_mtu_set, .promisc_mode_set = sock_mmap_promisc_mode_set, .promisc_mode_get = sock_mmap_promisc_mode_get, .mac_get = sock_mmap_mac_addr_get, -- cgit v1.2.3 From b6829f95ba5cb26689f0cad0054887d7b507c94d Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 15 Jan 2021 09:21:19 +0200 Subject: linux-gen: pcap: implement odp_pktio_maxlen_set() Implementation of odp_pktio_maxlen_set() for pcap pktio. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/pcap.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c index f80242a70..ffb6fab68 100644 --- a/platform/linux-generic/pktio/pcap.c +++ b/platform/linux-generic/pktio/pcap.c @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -57,6 +58,7 @@ typedef struct { void *tx; /**< tx pcap handle */ void *tx_dump; /**< tx pcap dumper handle */ odp_pool_t pool; /**< rx pool */ + uint32_t mtu; /**< link MTU */ int loops; /**< number of times to loop rx pcap */ int loop_cnt; /**< number of loops completed */ odp_bool_t promisc; /**< promiscuous mode state */ @@ -70,7 +72,9 @@ static inline pkt_pcap_t *pkt_priv(pktio_entry_t *pktio_entry) return (pkt_pcap_t *)(uintptr_t)(pktio_entry->s.pkt_priv); } -#define PKTIO_PCAP_MTU (64 * 1024) +#define PKTIO_PCAP_MTU_MIN (68 + _ODP_ETHHDR_LEN) +#define PKTIO_PCAP_MTU_MAX (64 * 1024) + static const char pcap_mac[] = {0x02, 0xe9, 0x34, 0x80, 0x73, 0x04}; static int pcapif_stats_reset(pktio_entry_t *pktio_entry); @@ -132,7 +136,7 @@ static int _pcapif_init_tx(pkt_pcap_t *pcap) if (!tx) { /* if there is no rx pcap_t already open for rx, a dummy * one needs to be opened for writing the dump */ - tx = pcap_open_dead(DLT_EN10MB, PKTIO_PCAP_MTU); + tx = pcap_open_dead(DLT_EN10MB, PKTIO_PCAP_MTU_MAX); if (!tx) { ODP_ERR("failed to open TX dump\n"); return -1; @@ -162,6 +166,7 @@ static int pcapif_init(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, pcap->loops = 1; pcap->pool = pool; pcap->promisc = 1; + pcap->mtu = PKTIO_PCAP_MTU_MAX; ret = _pcapif_parse_devname(pcap, devname); @@ -323,7 +328,7 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, int index ODP_UNUSED, static int _pcapif_dump_pkt(pkt_pcap_t *pcap, odp_packet_t pkt) { struct pcap_pkthdr hdr; - uint8_t tx_buf[PKTIO_PCAP_MTU]; + uint8_t tx_buf[PKTIO_PCAP_MTU_MAX]; if (!pcap->tx_dump) return 0; @@ -351,9 +356,9 @@ static int pcapif_send_pkt(pktio_entry_t *pktio_entry, int index ODP_UNUSED, odp_ticketlock_lock(&pktio_entry->s.txl); for (i = 0; i < num; ++i) { - int pkt_len = odp_packet_len(pkts[i]); + uint32_t pkt_len = odp_packet_len(pkts[i]); - if (pkt_len > PKTIO_PCAP_MTU) { + if (odp_unlikely(pkt_len > pcap->mtu)) { if (i == 0) { odp_ticketlock_unlock(&pktio_entry->s.txl); return -1; @@ -381,7 +386,19 @@ static int pcapif_send_pkt(pktio_entry_t *pktio_entry, int index ODP_UNUSED, static uint32_t pcapif_mtu_get(pktio_entry_t *pktio_entry ODP_UNUSED) { - return PKTIO_PCAP_MTU; + pkt_pcap_t *pcap = pkt_priv(pktio_entry); + + return pcap->mtu; +} + +static int pcapif_mtu_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output ODP_UNUSED) +{ + pkt_pcap_t *pcap = pkt_priv(pktio_entry); + + pcap->mtu = maxlen_input; + + return 0; } static int pcapif_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED, @@ -400,6 +417,13 @@ static int pcapif_capability(pktio_entry_t *pktio_entry ODP_UNUSED, capa->max_input_queues = 1; capa->max_output_queues = 1; capa->set_op.op.promisc_mode = 1; + capa->set_op.op.maxlen = 1; + + capa->maxlen.equal = true; + capa->maxlen.min_input = PKTIO_PCAP_MTU_MIN; + capa->maxlen.max_input = PKTIO_PCAP_MTU_MAX; + capa->maxlen.min_output = PKTIO_PCAP_MTU_MIN; + capa->maxlen.max_output = PKTIO_PCAP_MTU_MAX; odp_pktio_config_init(&capa->config); capa->config.pktin.bit.ts_all = 1; @@ -509,6 +533,7 @@ const pktio_if_ops_t _odp_pcap_pktio_ops = { .recv = pcapif_recv_pkt, .send = pcapif_send_pkt, .maxlen_get = pcapif_mtu_get, + .maxlen_set = pcapif_mtu_set, .promisc_mode_set = pcapif_promisc_mode_set, .promisc_mode_get = pcapif_promisc_mode_get, .mac_get = pcapif_mac_addr_get, -- cgit v1.2.3 From 22c0492d6d62ade25b9d4f7269449d57a7861b68 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Mon, 18 Jan 2021 14:25:30 +0200 Subject: linux-gen: netmap: reduce the number of info prints Print netmap pktio info only in debug mode to reduce clutter when running validation tests. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/netmap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c index 30fc532fc..5ca475dc8 100644 --- a/platform/linux-generic/pktio/netmap.c +++ b/platform/linux-generic/pktio/netmap.c @@ -173,10 +173,9 @@ static int init_options(pktio_entry_t *pktio_entry) return -1; } - ODP_PRINT("netmap interface: %s\n", - pkt_priv(pktio_entry)->if_name); - ODP_PRINT(" num_rx_desc: %d\n", opt->nr_rx_slots); - ODP_PRINT(" num_tx_desc: %d\n", opt->nr_tx_slots); + ODP_DBG("netmap interface: %s\n", pkt_priv(pktio_entry)->if_name); + ODP_DBG(" num_rx_desc: %d\n", opt->nr_rx_slots); + ODP_DBG(" num_tx_desc: %d\n", opt->nr_tx_slots); return 0; } @@ -621,7 +620,7 @@ static int netmap_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, /* netmap uses only ethtool to get statistics counters */ err = _odp_ethtool_stats_get_fd(pkt_nm->sockfd, pkt_nm->if_name, &cur_stats); if (err) { - ODP_ERR("netmap pktio %s does not support statistics counters\n", + ODP_DBG("netmap pktio %s does not support statistics counters\n", pkt_nm->if_name); pktio_entry->s.stats_type = STATS_UNSUPPORTED; } else { -- cgit v1.2.3 From 2b9a154c8e1be06e86c2a969d51072a6b77e0dbe Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 15 Jan 2021 09:56:29 +0200 Subject: linux-gen: netmap: implement odp_pktio_maxlen_set() Implementation of odp_pktio_maxlen_set() for netmap pktio. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/netmap.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c index 5ca475dc8..a6bebaa11 100644 --- a/platform/linux-generic/pktio/netmap.c +++ b/platform/linux-generic/pktio/netmap.c @@ -1,5 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited - * Copyright (c) 2019-2020, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -86,6 +86,7 @@ typedef struct { odp_pool_t pool; /**< pool to alloc packets from */ uint32_t if_flags; /**< interface flags */ uint32_t mtu; /**< maximum transmission unit */ + uint32_t mtu_max; /**< maximum supported MTU value */ int sockfd; /**< control socket */ unsigned char if_mac[ETH_ALEN]; /**< eth mac address */ char nm_name[IF_NAMESIZE + 7]; /**< netmap: */ @@ -449,6 +450,13 @@ static void netmap_init_capability(pktio_entry_t *pktio_entry) } capa->set_op.op.promisc_mode = 1; + capa->set_op.op.maxlen = 1; + + capa->maxlen.equal = true; + capa->maxlen.min_input = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_input = pkt_nm->mtu_max; + capa->maxlen.min_output = _ODP_SOCKET_MTU_MIN; + capa->maxlen.max_output = pkt_nm->mtu_max; odp_pktio_config_init(&capa->config); capa->config.pktin.bit.ts_all = 1; @@ -531,6 +539,9 @@ static int netmap_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, ODP_ERR("Unable to read netmap buf size\n"); return -1; } + pkt_nm->mtu_max = _ODP_SOCKET_MTU_MAX; + if (pkt_nm->mtu_max > nm_buf_size) + pkt_nm->mtu_max = nm_buf_size; if (!pkt_nm->is_virtual) { sockfd = socket(AF_INET, SOCK_DGRAM, 0); @@ -586,6 +597,7 @@ static int netmap_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, "addresses may not be unique.\n"); pktio_entry->s.capa.max_input_queues = 1; + pktio_entry->s.capa.set_op.op.maxlen = 0; pktio_entry->s.capa.set_op.op.promisc_mode = 0; pkt_nm->mtu = nm_buf_size; pktio_entry->s.stats_type = STATS_UNSUPPORTED; @@ -1169,6 +1181,21 @@ static uint32_t netmap_mtu_get(pktio_entry_t *pktio_entry) return pkt_priv(pktio_entry)->mtu; } +static int netmap_mtu_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output ODP_UNUSED) +{ + pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); + int ret; + + ret = _odp_mtu_set_fd(pkt_nm->sockfd, pktio_entry->s.name, maxlen_input); + if (ret) + return ret; + + pkt_nm->mtu = maxlen_input; + + return 0; +} + static int netmap_promisc_mode_set(pktio_entry_t *pktio_entry, odp_bool_t enable) { @@ -1261,6 +1288,7 @@ const pktio_if_ops_t netmap_pktio_ops = { .stats = netmap_stats, .stats_reset = netmap_stats_reset, .maxlen_get = netmap_mtu_get, + .maxlen_set = netmap_mtu_set, .promisc_mode_set = netmap_promisc_mode_set, .promisc_mode_get = netmap_promisc_mode_get, .mac_get = netmap_mac_addr_get, -- cgit v1.2.3 From 9dc961deacfbb77e138fabbdc8122d7270130f2a Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 15 Jan 2021 14:41:00 +0200 Subject: linux-gen: dpdk: reduce the number of info prints Print DPDK pktio info only in debug mode to reduce clutter when running validation tests. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/dpdk.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index 252437000..e2f1f100d 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -216,11 +216,11 @@ static int init_options(pktio_entry_t *pktio_entry, return -1; opt->set_flow_hash = !!val; - ODP_PRINT("DPDK interface (%s): %" PRIu16 "\n", dev_info->driver_name, - pkt_priv(pktio_entry)->port_id); - ODP_PRINT(" num_rx_desc: %d\n", opt->num_rx_desc); - ODP_PRINT(" num_tx_desc: %d\n", opt->num_tx_desc); - ODP_PRINT(" rx_drop_en: %d\n", opt->rx_drop_en); + ODP_DBG("DPDK interface (%s): %" PRIu16 "\n", dev_info->driver_name, + pkt_priv(pktio_entry)->port_id); + ODP_DBG(" num_rx_desc: %d\n", opt->num_rx_desc); + ODP_DBG(" num_tx_desc: %d\n", opt->num_tx_desc); + ODP_DBG(" rx_drop_en: %d\n", opt->rx_drop_en); return 0; } @@ -1805,7 +1805,7 @@ static void dpdk_ptype_support_set(pktio_entry_t *pktio_entry, uint16_t port_id) max_num = rte_eth_dev_get_supported_ptypes(port_id, mask, NULL, 0); if (max_num <= 0) { - ODP_ERR("Device does not support any ptype flags\n"); + ODP_DBG("Device does not support any ptype flags\n"); return; } @@ -1813,7 +1813,7 @@ static void dpdk_ptype_support_set(pktio_entry_t *pktio_entry, uint16_t port_id) num = rte_eth_dev_get_supported_ptypes(port_id, mask, ptype, max_num); if (num <= 0) { - ODP_ERR("Device does not support any ptype flags\n"); + ODP_DBG("Device does not support any ptype flags\n"); return; } -- cgit v1.2.3 From 61a57f9c69a23945d60c1606114f757ab3d824be Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 15 Jan 2021 10:21:00 +0200 Subject: linux-gen: dpdk: implement odp_pktio_maxlen_set() Implementation of odp_pktio_maxlen_set() for dpdk pktio. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- platform/linux-generic/pktio/dpdk.c | 100 ++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index e2f1f100d..97fb6ef1d 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -1,5 +1,5 @@ /* Copyright (c) 2016-2018, Linaro Limited - * Copyright (c) 2019-2020, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -104,6 +104,14 @@ ODP_STATIC_ASSERT((DPDK_NB_MBUF % DPDK_MEMPOOL_CACHE_SIZE == 0) && /* Minimum RX burst size */ #define DPDK_MIN_RX_BURST 4 +/* Limits for setting link MTU */ +#if RTE_VERSION >= RTE_VERSION_NUM(19, 11, 0, 0) +#define DPDK_MTU_MIN (RTE_ETHER_MIN_MTU + _ODP_ETHHDR_LEN) +#else +#define DPDK_MTU_MIN (68 + _ODP_ETHHDR_LEN) +#endif +#define DPDK_MTU_MAX (9000 + _ODP_ETHHDR_LEN) + /** DPDK runtime configuration options */ typedef struct { int num_rx_desc; @@ -126,19 +134,21 @@ typedef union ODP_ALIGNED_CACHE { /** Packet IO using DPDK interface */ typedef struct ODP_ALIGNED_CACHE { - odp_pool_t pool; /**< pool to alloc packets from */ - struct rte_mempool *pkt_pool; /**< DPDK packet pool */ - uint32_t data_room; /**< maximum packet length */ - unsigned int min_rx_burst; /**< minimum RX burst size */ - odp_pktin_hash_proto_t hash; /**< Packet input hash protocol */ + odp_pool_t pool; /**< pool to alloc packets from */ + struct rte_mempool *pkt_pool; /**< DPDK packet pool */ + uint32_t data_room; /**< maximum packet length */ + unsigned int min_rx_burst; /**< minimum RX burst size */ + odp_pktin_hash_proto_t hash; /**< Packet input hash protocol */ /* Supported RTE_PTYPE_XXX flags in a mask */ uint32_t supported_ptypes; - uint16_t mtu; /**< maximum transmission unit */ - uint16_t port_id; /**< DPDK port identifier */ + uint16_t mtu; /**< maximum transmission unit */ + uint32_t mtu_max; /**< maximum supported MTU value */ + odp_bool_t mtu_set; /**< DPDK MTU has been modified */ + uint16_t port_id; /**< DPDK port identifier */ /** Use system call to get/set vdev promisc mode */ uint8_t vdev_sysc_promisc; - uint8_t lockless_rx; /**< no locking for rx */ - uint8_t lockless_tx; /**< no locking for tx */ + uint8_t lockless_rx; /**< no locking for rx */ + uint8_t lockless_tx; /**< no locking for tx */ /** RX queue locks */ odp_ticketlock_t rx_lock[PKTIO_MAX_QUEUES] ODP_ALIGNED_CACHE; odp_ticketlock_t tx_lock[PKTIO_MAX_QUEUES]; /**< TX queue locks */ @@ -793,7 +803,7 @@ static inline int pkt_to_mbuf(pktio_entry_t *pktio_entry, pkt_len = packet_len(pkt_hdr); - if (pkt_len > pkt_dpdk->mtu) { + if (odp_unlikely(pkt_len > pkt_dpdk->mtu)) { if (i == 0) __odp_errno = EMSGSIZE; goto fail; @@ -1048,13 +1058,33 @@ static uint32_t dpdk_mtu_get(pktio_entry_t *pktio_entry) return mtu; } -static uint32_t dpdk_frame_maxlen(pktio_entry_t *pktio_entry) +static uint32_t dpdk_maxlen(pktio_entry_t *pktio_entry) { pkt_dpdk_t *pkt_dpdk = pkt_priv(pktio_entry); return pkt_dpdk->mtu; } +static int dpdk_maxlen_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, + uint32_t maxlen_output ODP_UNUSED) +{ + pkt_dpdk_t *pkt_dpdk = pkt_priv(pktio_entry); + uint16_t mtu; + int ret; + + /* DPDK MTU value does not include Ethernet header */ + mtu = maxlen_input - _ODP_ETHHDR_LEN; + + ret = rte_eth_dev_set_mtu(pkt_dpdk->port_id, mtu); + if (odp_unlikely(ret)) + ODP_ERR("rte_eth_dev_set_mtu() failed: %d\n", ret); + + pkt_dpdk->mtu = maxlen_input; + pkt_dpdk->mtu_set = true; + + return ret; +} + static int dpdk_vdev_promisc_mode_get(uint16_t port_id) { struct rte_eth_dev_info dev_info; @@ -1491,7 +1521,7 @@ static int dpdk_output_queues_config(pktio_entry_t *pktio_entry, } static int dpdk_init_capability(pktio_entry_t *pktio_entry, - struct rte_eth_dev_info *dev_info) + const struct rte_eth_dev_info *dev_info) { pkt_dpdk_t *pkt_dpdk = pkt_priv(pktio_entry); odp_pktio_capability_t *capa = &pktio_entry->s.capa; @@ -1503,10 +1533,8 @@ static int dpdk_init_capability(pktio_entry_t *pktio_entry, int ret; uint32_t ptype_mask = RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK; - memset(dev_info, 0, sizeof(struct rte_eth_dev_info)); memset(capa, 0, sizeof(odp_pktio_capability_t)); - rte_eth_dev_info_get(pkt_dpdk->port_id, dev_info); capa->max_input_queues = RTE_MIN(dev_info->max_rx_queues, PKTIO_MAX_QUEUES); @@ -1530,6 +1558,20 @@ static int dpdk_init_capability(pktio_entry_t *pktio_entry, return -1; } + /* Check if setting MTU is supported */ + ret = rte_eth_dev_set_mtu(pkt_dpdk->port_id, pkt_dpdk->mtu - _ODP_ETHHDR_LEN); + if (ret == 0) { + capa->set_op.op.maxlen = 1; + capa->maxlen.equal = true; + capa->maxlen.min_input = DPDK_MTU_MIN; + capa->maxlen.max_input = pkt_dpdk->mtu_max; + capa->maxlen.min_output = DPDK_MTU_MIN; + capa->maxlen.max_output = pkt_dpdk->mtu_max; + } else if (ret != -ENOTSUP) { + ODP_ERR("Failed to set interface MTU: %d\n", ret); + return -1; + } + ptype_cnt = rte_eth_dev_get_supported_ptypes(pkt_dpdk->port_id, ptype_mask, NULL, 0); if (ptype_cnt > 0) { @@ -1670,10 +1712,8 @@ static int dpdk_open(odp_pktio_t id ODP_UNUSED, return -1; } - if (dpdk_init_capability(pktio_entry, &dev_info)) { - ODP_ERR("Failed to initialize capability\n"); - return -1; - } + memset(&dev_info, 0, sizeof(struct rte_eth_dev_info)); + rte_eth_dev_info_get(pkt_dpdk->port_id, &dev_info); /* Initialize runtime options */ if (init_options(pktio_entry, &dev_info)) { @@ -1687,6 +1727,8 @@ static int dpdk_open(odp_pktio_t id ODP_UNUSED, return -1; } pkt_dpdk->mtu = mtu + _ODP_ETHHDR_LEN; + pkt_dpdk->mtu_max = RTE_MAX(pkt_dpdk->mtu, DPDK_MTU_MAX); + pkt_dpdk->mtu_set = false; promisc_mode_check(pkt_dpdk); @@ -1731,7 +1773,13 @@ static int dpdk_open(odp_pktio_t id ODP_UNUSED, pkt_dpdk->data_room -= pktio_entry->s.pktin_frame_offset; /* Mbuf chaining not yet supported */ - pkt_dpdk->mtu = RTE_MIN(pkt_dpdk->mtu, pkt_dpdk->data_room); + pkt_dpdk->mtu = RTE_MIN(pkt_dpdk->mtu, pkt_dpdk->data_room); + pkt_dpdk->mtu_max = RTE_MIN(pkt_dpdk->mtu_max, pkt_dpdk->data_room); + + if (dpdk_init_capability(pktio_entry, &dev_info)) { + ODP_ERR("Failed to initialize capability\n"); + return -1; + } for (i = 0; i < PKTIO_MAX_QUEUES; i++) { odp_ticketlock_init(&pkt_dpdk->rx_lock[i]); @@ -1866,6 +1914,15 @@ static int dpdk_start(pktio_entry_t *pktio_entry) if (dpdk_setup_eth_rx(pktio_entry, pkt_dpdk, &dev_info)) return -1; + /* Restore MTU value resetted by dpdk_setup_eth_rx() */ + if (pkt_dpdk->mtu_set && pktio_entry->s.capa.set_op.op.maxlen) { + ret = dpdk_maxlen_set(pktio_entry, pkt_dpdk->mtu, 0); + if (ret) { + ODP_ERR("Restoring device MTU failed: err=%d, port=%" PRIu8 "\n", + ret, port_id); + return -1; + } + } /* Start device */ ret = rte_eth_dev_start(port_id); if (ret < 0) { @@ -2185,7 +2242,8 @@ const pktio_if_ops_t dpdk_pktio_ops = { .send = dpdk_send, .link_status = dpdk_link_status, .link_info = dpdk_link_info, - .maxlen_get = dpdk_frame_maxlen, + .maxlen_get = dpdk_maxlen, + .maxlen_set = dpdk_maxlen_set, .promisc_mode_set = dpdk_promisc_mode_set, .promisc_mode_get = dpdk_promisc_mode_get, .mac_get = dpdk_mac_addr_get, -- cgit v1.2.3 From 72df9eb77cfdb5ccde244ed2d5561a3ede3445bf Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 22 Jan 2021 10:23:45 +0200 Subject: validation: pktio: add tests for new odp_pktio_maxlen_set() function Add validation tests for the new odp_pktio_maxlen_set() API. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- test/validation/api/pktio/pktio.c | 211 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 205 insertions(+), 6 deletions(-) diff --git a/test/validation/api/pktio/pktio.c b/test/validation/api/pktio/pktio.c index 074184a0b..47320e2e8 100644 --- a/test/validation/api/pktio/pktio.c +++ b/test/validation/api/pktio/pktio.c @@ -1,5 +1,5 @@ /* Copyright (c) 2014-2018, Linaro Limited - * Copyright (c) 2020, Nokia + * Copyright (c) 2020-2021, Nokia * Copyright (c) 2020, Marvell * All rights reserved. * @@ -1349,7 +1349,7 @@ static void pktio_test_recv_mtu(void) packet_len = PKT_LEN_NORMAL; } -static void pktio_test_mtu(void) +static void pktio_test_maxlen(void) { int ret; uint32_t maxlen; @@ -1361,13 +1361,119 @@ static void pktio_test_mtu(void) maxlen = odp_pktout_maxlen(pktio); CU_ASSERT(maxlen > 0); - printf(" %" PRIu32 " ", maxlen); - maxlen = odp_pktin_maxlen(pktio); CU_ASSERT(maxlen > 0); - printf(" %" PRIu32 " ", maxlen); + ret = odp_pktio_close(pktio); + CU_ASSERT(ret == 0); +} + +static int pktio_check_maxlen_set(void) +{ + odp_pktio_t pktio; + odp_pktio_capability_t capa; + odp_pktio_param_t pktio_param; + int ret; + + odp_pktio_param_init(&pktio_param); + pktio_param.in_mode = ODP_PKTIN_MODE_DIRECT; + pktio = odp_pktio_open(iface_name[0], pool[0], &pktio_param); + if (pktio == ODP_PKTIO_INVALID) + return ODP_TEST_INACTIVE; + + ret = odp_pktio_capability(pktio, &capa); + (void)odp_pktio_close(pktio); + + if (ret < 0 || !capa.set_op.op.maxlen) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static void pktio_test_maxlen_set(void) +{ + odp_pktio_capability_t capa; + int ret; + uint32_t maxlen, input_orig, output_orig; + + odp_pktio_t pktio = create_pktio(0, ODP_PKTIN_MODE_DIRECT, + ODP_PKTOUT_MODE_DIRECT); + CU_ASSERT_FATAL(pktio != ODP_PKTIO_INVALID); + + CU_ASSERT_FATAL(!odp_pktio_capability(pktio, &capa)); + + input_orig = odp_pktin_maxlen(pktio); + CU_ASSERT(input_orig > 0); + + output_orig = odp_pktout_maxlen(pktio); + CU_ASSERT(output_orig > 0); + + if (capa.maxlen.equal) { /* Input and output values have to be equal */ + CU_ASSERT(capa.maxlen.min_input == capa.maxlen.min_output); + CU_ASSERT(capa.maxlen.max_input == capa.maxlen.max_output); + CU_ASSERT(capa.maxlen.max_input > capa.maxlen.min_input); + + maxlen = capa.maxlen.min_input; + CU_ASSERT(!odp_pktio_maxlen_set(pktio, maxlen, maxlen)); + CU_ASSERT(odp_pktin_maxlen(pktio) == maxlen); + CU_ASSERT(odp_pktout_maxlen(pktio) == maxlen); + + maxlen = capa.maxlen.max_input; + CU_ASSERT(!odp_pktio_maxlen_set(pktio, maxlen, maxlen)); + CU_ASSERT(odp_pktin_maxlen(pktio) == maxlen); + CU_ASSERT(odp_pktout_maxlen(pktio) == maxlen); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, input_orig, input_orig)); + } else { + CU_ASSERT(capa.maxlen.max_input || capa.maxlen.max_output); + if (capa.maxlen.max_output == 0) { /* Only input supported */ + CU_ASSERT(capa.maxlen.min_output == 0); + CU_ASSERT(capa.maxlen.min_input < capa.maxlen.max_input); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, capa.maxlen.min_input, 0)); + CU_ASSERT(odp_pktin_maxlen(pktio) == capa.maxlen.min_input); + CU_ASSERT(!odp_pktio_maxlen_set(pktio, capa.maxlen.max_input, 0)); + CU_ASSERT(odp_pktin_maxlen(pktio) == capa.maxlen.max_input); + CU_ASSERT(!odp_pktio_maxlen_set(pktio, input_orig, 0)); + } else if (capa.maxlen.max_input == 0) { /* Only output supported */ + CU_ASSERT(capa.maxlen.min_input == 0); + CU_ASSERT(capa.maxlen.min_output < capa.maxlen.max_output); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, 0, capa.maxlen.min_output)); + CU_ASSERT(odp_pktout_maxlen(pktio) == capa.maxlen.min_output); + CU_ASSERT(!odp_pktio_maxlen_set(pktio, 0, capa.maxlen.max_output)); + CU_ASSERT(odp_pktout_maxlen(pktio) == capa.maxlen.max_output); + CU_ASSERT(!odp_pktio_maxlen_set(pktio, 0, output_orig)); + } else { /* Both directions supported */ + CU_ASSERT(capa.maxlen.min_input < capa.maxlen.max_input); + CU_ASSERT(capa.maxlen.min_output < capa.maxlen.max_output); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, capa.maxlen.min_input, + capa.maxlen.min_output)); + CU_ASSERT(odp_pktin_maxlen(pktio) == capa.maxlen.min_input); + CU_ASSERT(odp_pktout_maxlen(pktio) == capa.maxlen.min_output); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, capa.maxlen.max_input, + capa.maxlen.max_output)); + CU_ASSERT(odp_pktin_maxlen(pktio) == capa.maxlen.max_input); + CU_ASSERT(odp_pktout_maxlen(pktio) == capa.maxlen.max_output); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, capa.maxlen.max_input, + capa.maxlen.min_output)); + CU_ASSERT(odp_pktin_maxlen(pktio) == capa.maxlen.max_input); + CU_ASSERT(odp_pktout_maxlen(pktio) == capa.maxlen.min_output); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, capa.maxlen.min_input, + capa.maxlen.max_output)); + CU_ASSERT(odp_pktin_maxlen(pktio) == capa.maxlen.min_input); + CU_ASSERT(odp_pktout_maxlen(pktio) == capa.maxlen.max_output); + + CU_ASSERT(!odp_pktio_maxlen_set(pktio, input_orig, output_orig)); + } + } + CU_ASSERT(odp_pktin_maxlen(pktio) == input_orig); + CU_ASSERT(odp_pktout_maxlen(pktio) == output_orig); ret = odp_pktio_close(pktio); CU_ASSERT(ret == 0); } @@ -3272,6 +3378,95 @@ static void pktio_test_pktv_pktin_queue_config_sched(void) pktio_test_pktv_pktin_queue_config(ODP_PKTIN_MODE_SCHED); } +static void pktio_test_recv_maxlen_set(void) +{ + odp_pktio_t pktio_tx, pktio_rx; + odp_pktio_t pktio[MAX_NUM_IFACES]; + pktio_info_t pktio_rx_info; + odp_pktio_capability_t capa; + odp_pktio_config_t config; + odp_pktout_queue_t pktout_queue; + odp_packet_t pkt_tbl[TX_BATCH_LEN]; + uint32_t pkt_seq[TX_BATCH_LEN]; + uint32_t max_len = PKT_LEN_MAX; + int num_rx = 0; + int ret; + int i; + + CU_ASSERT_FATAL(num_ifaces >= 1); + + /* Open and configure interfaces */ + for (i = 0; i < num_ifaces; i++) { + uint32_t maxlen_tmp; + + pktio[i] = create_pktio(i, ODP_PKTIN_MODE_DIRECT, ODP_PKTOUT_MODE_DIRECT); + CU_ASSERT_FATAL(pktio[i] != ODP_PKTIO_INVALID); + + CU_ASSERT_FATAL(!odp_pktio_capability(pktio[i], &capa)); + CU_ASSERT_FATAL(capa.set_op.op.maxlen); + + odp_pktio_config_init(&config); + CU_ASSERT_FATAL(!odp_pktio_config(pktio[i], &config)); + + maxlen_tmp = capa.maxlen.max_input; + if (maxlen_tmp == 0) + maxlen_tmp = odp_pktin_maxlen(pktio[i]); + if (maxlen_tmp < max_len) + max_len = maxlen_tmp; + + maxlen_tmp = capa.maxlen.max_output; + if (maxlen_tmp == 0) + maxlen_tmp = odp_pktout_maxlen(pktio[i]); + if (maxlen_tmp < max_len) + max_len = maxlen_tmp; + + CU_ASSERT_FATAL(!odp_pktio_maxlen_set(pktio[i], capa.maxlen.max_input, + capa.maxlen.max_output)); + + CU_ASSERT_FATAL(odp_pktio_start(pktio[i]) == 0); + } + + for (i = 0; i < num_ifaces; i++) + _pktio_wait_linkup(pktio[i]); + + pktio_tx = pktio[0]; + pktio_rx = (num_ifaces > 1) ? pktio[1] : pktio_tx; + pktio_rx_info.id = pktio_rx; + pktio_rx_info.inq = ODP_QUEUE_INVALID; + pktio_rx_info.in_mode = ODP_PKTIN_MODE_DIRECT; + + packet_len = max_len; + ret = create_packets(pkt_tbl, pkt_seq, TX_BATCH_LEN, pktio_tx, + pktio_rx); + CU_ASSERT_FATAL(ret == TX_BATCH_LEN); + + ret = odp_pktout_queue(pktio_tx, &pktout_queue, 1); + CU_ASSERT_FATAL(ret > 0); + + /* Send packets one at a time and add delay between the packets */ + for (i = 0; i < TX_BATCH_LEN; i++) { + CU_ASSERT_FATAL(odp_pktout_send(pktout_queue, + &pkt_tbl[i], 1) == 1); + ret = wait_for_packets(&pktio_rx_info, &pkt_tbl[i], &pkt_seq[i], + 1, TXRX_MODE_SINGLE, ODP_TIME_SEC_IN_NS, false); + if (ret != 1) + break; + } + num_rx = i; + CU_ASSERT(num_rx == TX_BATCH_LEN); + + if (num_rx) + odp_packet_free_multi(pkt_tbl, num_rx); + + for (i = 0; i < num_ifaces; i++) { + CU_ASSERT_FATAL(!odp_pktio_stop(pktio[i])); + CU_ASSERT_FATAL(!odp_pktio_close(pktio[i])); + } + + /* Restore global variable */ + packet_len = PKT_LEN_NORMAL; +} + static int pktio_suite_init(void) { int i; @@ -3415,7 +3610,9 @@ odp_testinfo_t pktio_suite_unsegmented[] = { ODP_TEST_INFO(pktio_test_recv_tmo), ODP_TEST_INFO(pktio_test_recv_mq_tmo), ODP_TEST_INFO(pktio_test_recv_mtu), - ODP_TEST_INFO(pktio_test_mtu), + ODP_TEST_INFO(pktio_test_maxlen), + ODP_TEST_INFO_CONDITIONAL(pktio_test_maxlen_set, + pktio_check_maxlen_set), ODP_TEST_INFO(pktio_test_promisc), ODP_TEST_INFO(pktio_test_mac), ODP_TEST_INFO_CONDITIONAL(pktio_test_start_stop, @@ -3455,6 +3652,8 @@ odp_testinfo_t pktio_suite_unsegmented[] = { pktio_check_chksum_out_sctp), ODP_TEST_INFO_CONDITIONAL(pktio_test_chksum_out_sctp_ovr, pktio_check_chksum_out_sctp), + ODP_TEST_INFO_CONDITIONAL(pktio_test_recv_maxlen_set, + pktio_check_maxlen_set), ODP_TEST_INFO_NULL }; -- cgit v1.2.3 From 771045ccbfc8a2a1a0deff3bcc9e95387294e978 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 5 Feb 2021 16:09:53 +0200 Subject: helper: increment library version to 1.0.5 Increment helper library version number to reflect the addition of new IPsec algorithm support check function odph_ipsec_alg_check(). Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ce267a7b7..d00df726e 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ AC_SUBST(ODP_VERSION_API_MINOR) ########################################################################## m4_define([odph_version_generation], [1]) m4_define([odph_version_major], [0]) -m4_define([odph_version_minor], [4]) +m4_define([odph_version_minor], [5]) m4_define([odph_version], [odph_version_generation.odph_version_major.odph_version_minor]) -- cgit v1.2.3 From 8cd9049582bdf1a9f37e6df57952505b44b03101 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 5 Feb 2021 15:36:14 +0200 Subject: api: increment ODP API version to 1.26.0 Increment API version number to reflect the following changes: Backward-incompatible: - Only ODP_SCHED_NO_WAIT variants of schedule calls are allowed after calling odp_schedule_pause() - IPsec config must have been completed before enabling inbound inline IPsec in pktio Backward-compatible: - New odp_pktio_maxlen_set() function (and related capabilities) for configuring input/output maximum frame lengths - New Large Send Offload (LSO) APIs - Clarify odp_schedule_capability_t.max_groups capability definition - Added configure option to enable/disable predefined scheduling groups Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d00df726e..20d5af648 100644 --- a/configure.ac +++ b/configure.ac @@ -3,8 +3,8 @@ AC_PREREQ([2.5]) # ODP API version ########################################################################## m4_define([odpapi_generation_version], [1]) -m4_define([odpapi_major_version], [25]) -m4_define([odpapi_minor_version], [2]) +m4_define([odpapi_major_version], [26]) +m4_define([odpapi_minor_version], [0]) m4_define([odpapi_point_version], [0]) m4_define([odpapi_version], [odpapi_generation_version.odpapi_major_version.odpapi_minor_version.odpapi_point_version]) -- cgit v1.2.3 From 2087893b237bfea212838c21172d323a842ae2ae Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 5 Feb 2021 17:06:59 +0200 Subject: test: mem_perf: check num cpus with all workers option All available worker cpus are used with -c 0 option. Ensure that the number of workers does not exceed maximum size of the tables. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- test/performance/odp_mem_perf.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/performance/odp_mem_perf.c b/test/performance/odp_mem_perf.c index a833a04e8..0470d337a 100644 --- a/test/performance/odp_mem_perf.c +++ b/test/performance/odp_mem_perf.c @@ -135,7 +135,7 @@ static int parse_options(int argc, char *argv[], test_options_t *test_options) static int set_num_cpu(test_global_t *global) { - int ret; + int ret, max_num; test_options_t *test_options = &global->test_options; int num_cpu = test_options->num_cpu; @@ -145,7 +145,11 @@ static int set_num_cpu(test_global_t *global) return -1; } - ret = odp_cpumask_default_worker(&global->cpumask, num_cpu); + max_num = num_cpu; + if (num_cpu == 0) + max_num = ODP_THREAD_COUNT_MAX - 1; + + ret = odp_cpumask_default_worker(&global->cpumask, max_num); if (num_cpu && ret != num_cpu) { ODPH_ERR("Too many workers. Max supported %i.\n", ret); @@ -154,6 +158,11 @@ static int set_num_cpu(test_global_t *global) /* Zero: all available workers */ if (num_cpu == 0) { + if (ret > max_num) { + ODPH_ERR("Too many cpus from odp_cpumask_default_worker(): %i\n", ret); + return -1; + } + num_cpu = ret; test_options->num_cpu = num_cpu; } -- cgit v1.2.3 From 15f98089974e620529c20a0ed50ab62090057e54 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 5 Feb 2021 15:56:09 +0200 Subject: example: debug: add debug print API calls Add calls to odp_pktio_print(), odp_packet_print_data(), odp_ipsec_print() and odp_sys_config_print(). Move system info print under -S option. Use ODPH_ERR() instead of printf() to report errors. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- example/debug/odp_debug.c | 187 +++++++++++++++++++++++++++++++++------------- 1 file changed, 133 insertions(+), 54 deletions(-) diff --git a/example/debug/odp_debug.c b/example/debug/odp_debug.c index ef9597906..1f2c7a8a2 100644 --- a/example/debug/odp_debug.c +++ b/example/debug/odp_debug.c @@ -1,20 +1,24 @@ -/* Copyright (c) 2020, Nokia +/* Copyright (c) 2020-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include #include #include #include #include +#include typedef struct test_global_t { + int system; int shm; - int shm_all; int pool; int queue; + int pktio; + int ipsec; } test_global_t; @@ -27,10 +31,12 @@ static void print_usage(void) "are called when no options are given.\n" "\n" "OPTIONS:\n" - " -S, --shm_all Call odp_shm_print_all()\n" + " -S, --system Call odp_sys_info_print() and odp_sys_config_print()\n" " -s, --shm Create a SHM and call odp_shm_print()\n" " -p, --pool Create various types of pools and call odp_pool_print()\n" " -q, --queue Create various types of queues and call odp_queue_print()\n" + " -i, --interface Create packet IO interface (loop) and call odp_pktio_print()\n" + " -I, --ipsec Call odp_ipsec_print()\n" " -h, --help Display help and exit.\n\n"); } @@ -39,14 +45,16 @@ static int parse_options(int argc, char *argv[], test_global_t *global) int opt, long_index; const struct option longopts[] = { - {"shm_all", no_argument, NULL, 'S'}, + {"system", no_argument, NULL, 'S'}, {"shm", no_argument, NULL, 's'}, {"pool", no_argument, NULL, 'p'}, {"queue", no_argument, NULL, 'q'}, + {"interface", no_argument, NULL, 'i'}, + {"ipsec", no_argument, NULL, 'I'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; - const char *shortopts = "+Sspqh"; + const char *shortopts = "+SspqiIh"; int ret = 0; while (1) { @@ -57,7 +65,7 @@ static int parse_options(int argc, char *argv[], test_global_t *global) switch (opt) { case 'S': - global->shm_all = 1; + global->system = 1; break; case 's': global->shm = 1; @@ -68,6 +76,12 @@ static int parse_options(int argc, char *argv[], test_global_t *global) case 'q': global->queue = 1; break; + case 'i': + global->pktio = 1; + break; + case 'I': + global->ipsec = 1; + break; case 'h': default: print_usage(); @@ -78,32 +92,26 @@ static int parse_options(int argc, char *argv[], test_global_t *global) return ret; } -static int shm_debug(test_global_t *global) +static int shm_debug(void) { const char *name = "debug_shm"; odp_shm_t shm = ODP_SHM_INVALID; - if (global->shm) { - shm = odp_shm_reserve(name, 8 * 1024, 64, 0); - if (shm == ODP_SHM_INVALID) { - printf("SHM reserve failed: %s\n", name); - return -1; - } + shm = odp_shm_reserve(name, 8 * 1024, 64, 0); + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("SHM reserve failed: %s\n", name); + return -1; } - if (global->shm_all) { - printf("\n"); - odp_shm_print_all(); - } + printf("\n"); + odp_shm_print_all(); - if (global->shm) { - printf("\n"); - odp_shm_print(shm); + printf("\n"); + odp_shm_print(shm); - if (odp_shm_free(shm)) { - printf("SHM free failed: %s\n", name); - return -1; - } + if (odp_shm_free(shm)) { + ODPH_ERR("SHM free failed: %s\n", name); + return -1; } return 0; @@ -114,7 +122,7 @@ static int buffer_debug(odp_pool_t pool) odp_buffer_t buf = odp_buffer_alloc(pool); if (buf == ODP_BUFFER_INVALID) { - printf("Buffer alloc failed\n"); + ODPH_ERR("Buffer alloc failed\n"); return -1; } @@ -131,13 +139,16 @@ static int packet_debug(odp_pool_t pool, int len) odp_packet_t pkt = odp_packet_alloc(pool, len); if (pkt == ODP_PACKET_INVALID) { - printf("Packet alloc failed\n"); + ODPH_ERR("Packet alloc failed\n"); return -1; } printf("\n"); odp_packet_print(pkt); + printf("\n"); + odp_packet_print_data(pkt, 0, len); + odp_packet_free(pkt); return 0; @@ -159,7 +170,7 @@ static int pool_debug(void) pool = odp_pool_create(name, ¶m); if (pool == ODP_POOL_INVALID) { - printf("Pool create failed: %s\n", name); + ODPH_ERR("Pool create failed: %s\n", name); return -1; } @@ -170,7 +181,7 @@ static int pool_debug(void) return -1; if (odp_pool_destroy(pool)) { - printf("Pool destroy failed: %s\n", name); + ODPH_ERR("Pool destroy failed: %s\n", name); return -1; } @@ -184,7 +195,7 @@ static int pool_debug(void) pool = odp_pool_create(name, ¶m); if (pool == ODP_POOL_INVALID) { - printf("Pool create failed: %s\n", name); + ODPH_ERR("Pool create failed: %s\n", name); return -1; } @@ -195,7 +206,7 @@ static int pool_debug(void) return -1; if (odp_pool_destroy(pool)) { - printf("Pool destroy failed: %s\n", name); + ODPH_ERR("Pool destroy failed: %s\n", name); return -1; } @@ -207,7 +218,7 @@ static int pool_debug(void) pool = odp_pool_create(name, ¶m); if (pool == ODP_POOL_INVALID) { - printf("Pool create failed: %s\n", name); + ODPH_ERR("Pool create failed: %s\n", name); return -1; } @@ -215,7 +226,7 @@ static int pool_debug(void) odp_pool_print(pool); if (odp_pool_destroy(pool)) { - printf("Pool destroy failed: %s\n", name); + ODPH_ERR("Pool destroy failed: %s\n", name); return -1; } @@ -235,7 +246,7 @@ static int queue_debug(void) queue = odp_queue_create(name, ¶m); if (queue == ODP_QUEUE_INVALID) { - printf("Queue create failed: %s\n", name); + ODPH_ERR("Queue create failed: %s\n", name); return -1; } @@ -243,13 +254,13 @@ static int queue_debug(void) odp_queue_print(queue); if (odp_queue_destroy(queue)) { - printf("Queue destroy failed: %s\n", name); + ODPH_ERR("Queue destroy failed: %s\n", name); return -1; } /* Configure scheduler before creating any scheduled queues */ if (odp_schedule_config(NULL)) { - printf("Schedule config failed\n"); + ODPH_ERR("Schedule config failed\n"); return -1; } @@ -260,7 +271,7 @@ static int queue_debug(void) queue = odp_queue_create(name, ¶m); if (queue == ODP_QUEUE_INVALID) { - printf("Queue create failed: %s\n", name); + ODPH_ERR("Queue create failed: %s\n", name); return -1; } @@ -268,13 +279,63 @@ static int queue_debug(void) odp_queue_print(queue); if (odp_queue_destroy(queue)) { - printf("Queue destroy failed: %s\n", name); + ODPH_ERR("Queue destroy failed: %s\n", name); + return -1; + } + + return 0; +} + +static int pktio_debug(void) +{ + odp_pool_t pool; + odp_pool_param_t pool_param; + odp_pktio_t pktio; + int pkt_len = 100; + + odp_pool_param_init(&pool_param); + pool_param.type = ODP_POOL_PACKET; + pool_param.pkt.num = 10; + pool_param.pkt.len = pkt_len; + + pool = odp_pool_create("debug_pktio_pool", &pool_param); + + if (pool == ODP_POOL_INVALID) { + ODPH_ERR("Pool create failed\n"); + return -1; + } + + pktio = odp_pktio_open("loop", pool, NULL); + + if (pktio == ODP_PKTIO_INVALID) { + ODPH_ERR("Pktio open failed\n"); + return -1; + } + + printf("\n"); + odp_pktio_print(pktio); + + if (odp_pktio_close(pktio)) { + ODPH_ERR("Pktio close failed\n"); + return -1; + } + + if (odp_pool_destroy(pool)) { + ODPH_ERR("Pool destroy failed\n"); return -1; } return 0; } +static int ipsec_debug(void) +{ + printf("\n"); + odp_ipsec_print(); + + return 0; +} + int main(int argc, char *argv[]) { odp_instance_t inst; @@ -285,50 +346,68 @@ int main(int argc, char *argv[]) if (argc < 2) { /* If not arguments, run all test cases */ - global->shm_all = 1; + global->system = 1; global->shm = 1; global->pool = 1; global->queue = 1; + global->pktio = 1; + global->ipsec = 1; } else { if (parse_options(argc, argv, global)) return -1; } if (odp_init_global(&inst, NULL, NULL)) { - printf("Global init failed.\n"); - return -1; + ODPH_ERR("Global init failed.\n"); + exit(EXIT_FAILURE); } if (odp_init_local(inst, ODP_THREAD_CONTROL)) { - printf("Local init failed.\n"); - return -1; + ODPH_ERR("Local init failed.\n"); + exit(EXIT_FAILURE); } - odp_sys_info_print(); + if (global->system) { + printf("\n"); + odp_sys_info_print(); - if ((global->shm_all || global->shm) && shm_debug(global)) { - printf("SHM debug failed.\n"); - return -1; + printf("\n"); + odp_sys_config_print(); + } + + if (global->shm && shm_debug()) { + ODPH_ERR("SHM debug failed.\n"); + exit(EXIT_FAILURE); } if (global->pool && pool_debug()) { - printf("Pool debug failed.\n"); - return -1; + ODPH_ERR("Pool debug failed.\n"); + exit(EXIT_FAILURE); } if (global->queue && queue_debug()) { - printf("Queue debug failed.\n"); - return -1; + ODPH_ERR("Queue debug failed.\n"); + exit(EXIT_FAILURE); + } + + if (global->pktio && pktio_debug()) { + ODPH_ERR("Packet debug failed.\n"); + exit(EXIT_FAILURE); + } + + if (global->ipsec && ipsec_debug()) { + ODPH_ERR("IPSEC debug failed.\n"); + exit(EXIT_FAILURE); } if (odp_term_local()) { - printf("Local term failed.\n"); - return -1; + ODPH_ERR("Local term failed.\n"); + exit(EXIT_FAILURE); } if (odp_term_global(inst)) { - printf("Global term failed.\n"); - return -1; + ODPH_ERR("Global term failed.\n"); + exit(EXIT_FAILURE); } return 0; -- cgit v1.2.3 From 55452ad448fd5b1fc0c8213a2e5786f36da6eb64 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 5 Feb 2021 16:10:12 +0200 Subject: linux-gen: pktio: format pktio_print header Use the same style for odp_pktio_print() header that is used with other debug print functions: Pktio info ---------- Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- platform/linux-generic/odp_packet_io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index 846db868c..7353f6737 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -1656,8 +1656,7 @@ void odp_pktio_print(odp_pktio_t hdl) return; } - len += snprintf(&str[len], n - len, - "pktio\n"); + len += snprintf(&str[len], n - len, "Pktio info\n----------\n"); len += snprintf(&str[len], n - len, " name %s\n", entry->s.name); len += snprintf(&str[len], n - len, -- cgit v1.2.3 From 710ac1129430c54b988530fabeb0e3d5764c8768 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 5 Feb 2021 16:21:45 +0200 Subject: linux-gen: ipsec: add line feed to debug print Print output stands out better with line feeds around it. Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- platform/linux-generic/odp_ipsec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/linux-generic/odp_ipsec.c b/platform/linux-generic/odp_ipsec.c index f0bbaf167..57a0a167d 100644 --- a/platform/linux-generic/odp_ipsec.c +++ b/platform/linux-generic/odp_ipsec.c @@ -2142,7 +2142,7 @@ void odp_ipsec_print(void) { ODP_PRINT("\nIPSEC print\n"); ODP_PRINT("-----------\n"); - ODP_PRINT(" max number of SA %u\n", ipsec_config->max_num_sa); + ODP_PRINT(" max number of SA %u\n\n", ipsec_config->max_num_sa); } void odp_ipsec_sa_print(odp_ipsec_sa_t sa) @@ -2151,5 +2151,5 @@ void odp_ipsec_sa_print(odp_ipsec_sa_t sa) ODP_PRINT("\nIPSEC SA print\n"); ODP_PRINT("--------------\n"); - ODP_PRINT(" SPI %u\n", ipsec_sa->spi); + ODP_PRINT(" SPI %u\n\n", ipsec_sa->spi); } -- cgit v1.2.3 From 95075c29b05a1c1f99d245de6b6a57857d3b57d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Wed, 10 Feb 2021 14:21:36 +0200 Subject: linux-gen: remove doze() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit doze() is a trivial wrapper for odp_cpu_pause(). Remove it and call odp_cpu_pause() directly. Signed-off-by: Jere Leppänen Reviewed-by: Petri Savolainen --- platform/linux-generic/arch/aarch64/odp_cpu_idling.h | 6 ------ platform/linux-generic/arch/arm/odp_cpu_idling.h | 6 ------ platform/linux-generic/arch/default/odp_cpu_idling.h | 5 ----- platform/linux-generic/odp_queue_scalable.c | 7 ++++--- platform/linux-generic/odp_schedule_scalable.c | 14 +++++++------- 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/platform/linux-generic/arch/aarch64/odp_cpu_idling.h b/platform/linux-generic/arch/aarch64/odp_cpu_idling.h index 8528c8591..a6cea8c63 100644 --- a/platform/linux-generic/arch/aarch64/odp_cpu_idling.h +++ b/platform/linux-generic/arch/aarch64/odp_cpu_idling.h @@ -30,12 +30,6 @@ static inline int wfe(void) return 1; } -static inline void doze(void) -{ - /* When using WFE do not stall the pipeline using other means */ - odp_cpu_pause(); -} - #define monitor128(addr, mo) lld((addr), (mo)) #define monitor64(addr, mo) ll64((addr), (mo)) #define monitor32(addr, mo) ll32((addr), (mo)) diff --git a/platform/linux-generic/arch/arm/odp_cpu_idling.h b/platform/linux-generic/arch/arm/odp_cpu_idling.h index 8528c8591..a6cea8c63 100644 --- a/platform/linux-generic/arch/arm/odp_cpu_idling.h +++ b/platform/linux-generic/arch/arm/odp_cpu_idling.h @@ -30,12 +30,6 @@ static inline int wfe(void) return 1; } -static inline void doze(void) -{ - /* When using WFE do not stall the pipeline using other means */ - odp_cpu_pause(); -} - #define monitor128(addr, mo) lld((addr), (mo)) #define monitor64(addr, mo) ll64((addr), (mo)) #define monitor32(addr, mo) ll32((addr), (mo)) diff --git a/platform/linux-generic/arch/default/odp_cpu_idling.h b/platform/linux-generic/arch/default/odp_cpu_idling.h index 70b8cae6e..9d23ad20d 100644 --- a/platform/linux-generic/arch/default/odp_cpu_idling.h +++ b/platform/linux-generic/arch/default/odp_cpu_idling.h @@ -28,9 +28,4 @@ static inline int wfe(void) #define monitor32(addr, mo) __atomic_load_n((addr), (mo)) #define monitor8(addr, mo) __atomic_load_n((addr), (mo)) -static inline void doze(void) -{ - odp_cpu_pause(); -} - #endif diff --git a/platform/linux-generic/odp_queue_scalable.c b/platform/linux-generic/odp_queue_scalable.c index 02bf9fbc2..abb3a97c2 100644 --- a/platform/linux-generic/odp_queue_scalable.c +++ b/platform/linux-generic/odp_queue_scalable.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -465,7 +466,7 @@ static int queue_destroy(odp_queue_t handle) sevl(); while (wfe() && monitor32((uint32_t *)&q->qschst.numevts, __ATOMIC_RELAXED) != 0) - doze(); + odp_cpu_pause(); } if (q->schedq != NULL) { @@ -573,7 +574,7 @@ static inline int _odp_queue_enq(sched_elem_t *q, sevl(); while (wfe() && monitor32(&q->cons_write, __ATOMIC_RELAXED) != old_write) - doze(); + odp_cpu_pause(); } /* Signal consumers that events are available (release events) @@ -803,7 +804,7 @@ inline int _odp_queue_deq(sched_elem_t *q, odp_buffer_hdr_t *buf_hdr[], int num) sevl(); while (wfe() && monitor32(&q->prod_read, __ATOMIC_RELAXED) != old_read) - doze(); + odp_cpu_pause(); } /* Signal producers that empty slots are available diff --git a/platform/linux-generic/odp_schedule_scalable.c b/platform/linux-generic/odp_schedule_scalable.c index 4da5c378d..2ba40256b 100644 --- a/platform/linux-generic/odp_schedule_scalable.c +++ b/platform/linux-generic/odp_schedule_scalable.c @@ -227,7 +227,7 @@ void _odp_sched_update_enq(sched_elem_t *q, uint32_t actual) while (wfe() && monitor8(&q->qschst.cur_ticket, __ATOMIC_ACQUIRE) != ticket) - doze(); + odp_cpu_pause(); } /* Enqueue at end of scheduler queue */ /* We are here because of empty-to-non-empty transition @@ -375,7 +375,7 @@ sched_update_deq(sched_elem_t *q, while (wfe() && monitor8(&q->qschst.cur_ticket, __ATOMIC_ACQUIRE) != ticket) - doze(); + odp_cpu_pause(); } /* We are here because of non-empty-to-empty transition or * WRR budget exhausted @@ -502,7 +502,7 @@ static inline void sched_update_popd(sched_elem_t *elem) sevl(); while (wfe() && monitor8(&elem->qschst.cur_ticket, __ATOMIC_ACQUIRE) != ticket) - doze(); + odp_cpu_pause(); } sched_update_popd_sc(elem); atomic_store_release(&elem->qschst.cur_ticket, ticket + 1, @@ -1074,7 +1074,7 @@ restart_same: while (wfe() && monitor32(&rwin->turn, __ATOMIC_ACQUIRE) != sn) - doze(); + odp_cpu_pause(); } #ifdef CONFIG_QSCHST_LOCK LOCK(&elem->qschlock); @@ -1162,7 +1162,7 @@ static void schedule_order_lock(uint32_t lock_index) while (wfe() && monitor32(&rctx->rwin->olock[lock_index], __ATOMIC_ACQUIRE) != rctx->sn) - doze(); + odp_cpu_pause(); } } @@ -1579,7 +1579,7 @@ static int schedule_group_destroy(odp_schedule_group_t group) !bitset_is_eql(wanted, bitset_monitor(&sg->thr_actual[p], __ATOMIC_RELAXED))) - doze(); + odp_cpu_pause(); } /* Else ignore because no ODP queues on this prio */ } @@ -2157,7 +2157,7 @@ static void order_lock(void) */ while (wfe() && monitor32(&rwin->hc.head, __ATOMIC_ACQUIRE) != sn) - doze(); + odp_cpu_pause(); } } -- cgit v1.2.3 From 596cec45ded4a9b9f0749292c30b96aef5b2ea7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Thu, 21 Jan 2021 17:46:11 +0200 Subject: linux-gen: introduce _ODP_UNALIGNED macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _ODP_UNALIGNED pre-processor macro is defined as 1 if the CPU features efficient unaligned memory access, 0 otherwise. Signed-off-by: Jere Leppänen Reviewed-by: Petri Savolainen --- platform/linux-generic/Makefile.am | 1 + platform/linux-generic/arch/aarch64/odp_cpu.h | 6 ++++++ platform/linux-generic/arch/arm/odp_cpu.h | 6 ++++++ platform/linux-generic/arch/default/odp_cpu.h | 4 ++++ platform/linux-generic/arch/x86/odp_cpu.h | 14 ++++++++++++++ 5 files changed, 31 insertions(+) create mode 100644 platform/linux-generic/arch/x86/odp_cpu.h diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 70ab7ab7c..a6095269f 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -352,6 +352,7 @@ if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/x86/odp/api/abi/cpu.h endif noinst_HEADERS += arch/x86/cpu_flags.h \ + arch/x86/odp_cpu.h \ arch/default/odp_cpu.h \ arch/default/odp_cpu_idling.h endif diff --git a/platform/linux-generic/arch/aarch64/odp_cpu.h b/platform/linux-generic/arch/aarch64/odp_cpu.h index 0da6e3c60..84bc4dffd 100644 --- a/platform/linux-generic/arch/aarch64/odp_cpu.h +++ b/platform/linux-generic/arch/aarch64/odp_cpu.h @@ -59,4 +59,10 @@ do { \ #include "odp_atomic.h" #include "odp_cpu_idling.h" +#ifdef __ARM_FEATURE_UNALIGNED +#define _ODP_UNALIGNED 1 +#else +#define _ODP_UNALIGNED 0 +#endif + #endif /* PLATFORM_LINUXGENERIC_ARCH_ARM_ODP_CPU_H */ diff --git a/platform/linux-generic/arch/arm/odp_cpu.h b/platform/linux-generic/arch/arm/odp_cpu.h index d3d2de34f..82d47325f 100644 --- a/platform/linux-generic/arch/arm/odp_cpu.h +++ b/platform/linux-generic/arch/arm/odp_cpu.h @@ -52,4 +52,10 @@ static inline void _odp_dmb(void) #include "odp_atomic.h" #include "odp_cpu_idling.h" +#ifdef __ARM_FEATURE_UNALIGNED +#define _ODP_UNALIGNED 1 +#else +#define _ODP_UNALIGNED 0 +#endif + #endif /* PLATFORM_LINUXGENERIC_ARCH_ARM_ODP_CPU_H */ diff --git a/platform/linux-generic/arch/default/odp_cpu.h b/platform/linux-generic/arch/default/odp_cpu.h index 18dd968fb..d8bc125c8 100644 --- a/platform/linux-generic/arch/default/odp_cpu.h +++ b/platform/linux-generic/arch/default/odp_cpu.h @@ -9,6 +9,10 @@ #ifndef ODP_DEFAULT_CPU_H_ #define ODP_DEFAULT_CPU_H_ +#ifndef _ODP_UNALIGNED +#define _ODP_UNALIGNED 0 +#endif + /****************************************************************************** * Atomics *****************************************************************************/ diff --git a/platform/linux-generic/arch/x86/odp_cpu.h b/platform/linux-generic/arch/x86/odp_cpu.h new file mode 100644 index 000000000..8f8f22daf --- /dev/null +++ b/platform/linux-generic/arch/x86/odp_cpu.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_X86_CPU_H_ +#define ODP_X86_CPU_H_ + +#define _ODP_UNALIGNED 1 + +#include + +#endif -- cgit v1.2.3 From 6709708360dc430277bf1f37b0f2203c5181438d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Tue, 22 Dec 2020 16:29:49 +0200 Subject: linux-gen: improve software checksum implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve software checksum implementation and put it in a separate header file so that it may be easily called from multiple places. Signed-off-by: Jere Leppänen Reviewed-by: Petri Savolainen --- platform/linux-generic/Makefile.am | 1 + .../linux-generic/include/odp_chksum_internal.h | 189 +++++++++++++++++++++ platform/linux-generic/odp_chksum.c | 26 +-- 3 files changed, 192 insertions(+), 24 deletions(-) create mode 100644 platform/linux-generic/include/odp_chksum_internal.h diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index a6095269f..00ea764de 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -96,6 +96,7 @@ noinst_HEADERS = \ include/odp_atomic_internal.h \ include/odp_bitset.h \ include/odp_buffer_internal.h \ + include/odp_chksum_internal.h \ include/odp_classification_datamodel.h \ include/odp_classification_internal.h \ include/odp_config_internal.h \ diff --git a/platform/linux-generic/include/odp_chksum_internal.h b/platform/linux-generic/include/odp_chksum_internal.h new file mode 100644 index 000000000..5a134ae2d --- /dev/null +++ b/platform/linux-generic/include/odp_chksum_internal.h @@ -0,0 +1,189 @@ +/* Copyright (c) 2020, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_CHKSUM_INTERNAL_H_ +#define ODP_CHKSUM_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/* + * Compute the final Internet checksum (RFC 1071) based on a partial + * sum. A partial sum can be obtained e.g. by calling + * chksum_partial(). + */ +static inline uint16_t chksum_finalize(uint64_t sum) +{ + sum = (sum >> 32) + (sum & 0xffffffff); + sum = (sum >> 16) + (sum & 0xffff); + /* + * The final & 0xffff is intentionally omitted, the extra bits + * are discarded by the implicit cast to the return type. + */ + return (sum >> 16) + sum; +} + +/* + * Compute a partial checksum. Several partial checksums may be summed + * together. The final checksum may be obtained by calling + * chksum_finalize(). Parameter offset is the offset of this segment + * of data from the start of IP header. + * + * This implementation + * + * - Accepts unaligned data. + * + * - Accepts data at any byte offset from the start of IP header, + * including odd offsets. + * + * - Uses unaligned memory access only if available. + * + * - Is optimized (for skylake, cn96, a53) by trial and error. + * + * The following did not improve performance (in synthetic tests): + * + * - 2 or 4 sub-sums in the main loop (to break dependency chains). + * + * - Aligning to 8 bytes instead of 4 (for ldp instruction). This + * makes the main loop faster on a53 (only), but the extra + * conditional branch has its cost. + * + * - __builtin_assume_aligned(). + */ +static uint64_t chksum_partial(const void *addr, uint32_t len, uint32_t offset) +{ + const uint8_t *b; + const uint16_t *w; + const uint32_t *d; + uint64_t sum = 0; + + /* + * Offset is either even or odd, the rest of it doesn't + * matter. + */ + offset &= 1; + + if (_ODP_UNALIGNED) { + /* + * We have efficient unaligned access. Just read + * dwords starting at the given address. + */ + d = (const uint32_t *)addr; + } else { + /* + * We must avoid unaligned access, so align to 4 bytes + * by summing up the first up to 3 bytes. + */ + b = (const uint8_t *)addr; + + if (odp_unlikely((uintptr_t)b & 1) && len >= 1) { + /* + * Align to 2 bytes by handling an odd + * byte. Since addr is unaligned, the first + * byte goes into the second byte of the sum. + */ + sum += odp_cpu_to_be_16(*b++); + len -= 1; + + /* An odd byte negates the effect of offset. */ + offset ^= 1; + } + + /* + * This cast increases alignment, but it's OK, since + * we've made sure that the pointer value is aligned. + */ + w = (const uint16_t *)(uintptr_t)b; + + if ((uintptr_t)w & 2 && len >= 2) { + /* Align bytes by handling an odd word. */ + sum += *w++; + len -= 2; + } + + /* Increases alignment. */ + d = (const uint32_t *)(uintptr_t)w; + } + + while (len >= 32) { + /* 8 dwords or 32 bytes per round. */ + + sum += *d++; + sum += *d++; + sum += *d++; + sum += *d++; + + sum += *d++; + sum += *d++; + sum += *d++; + sum += *d++; + + len -= 32; + } + + /* Last up to 7 dwords. */ + switch (len >> 2) { + case 7: + sum += *d++; + /* FALLTHROUGH */ + case 6: + sum += *d++; + /* FALLTHROUGH */ + case 5: + sum += *d++; + /* FALLTHROUGH */ + case 4: + sum += *d++; + /* FALLTHROUGH */ + case 3: + sum += *d++; + /* FALLTHROUGH */ + case 2: + sum += *d++; + /* FALLTHROUGH */ + case 1: + sum += *d++; + /* FALLTHROUGH */ + default: + break; + } + + len &= 3; + + w = (const uint16_t *)d; + if (len > 1) { + /* Last word. */ + sum += *w++; + len -= 2; + } + + if (len) { + /* Last byte. */ + b = (const uint8_t *)w; + sum += odp_cpu_to_be_16((uint16_t)*b << 8); + } + + /* + * If offset is odd, our sum is byte-flipped and we need to + * flip odd and even bytes. + */ + if (odp_unlikely(offset)) + sum = ((sum & 0xff00ff00ff00ff) << 8) | ((sum & 0xff00ff00ff00ff00) >> 8); + + return sum; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-generic/odp_chksum.c b/platform/linux-generic/odp_chksum.c index d018e33a3..a0336893e 100644 --- a/platform/linux-generic/odp_chksum.c +++ b/platform/linux-generic/odp_chksum.c @@ -6,31 +6,9 @@ #include #include +#include -/* Simple implementation of ones complement sum. - * Based on RFC1071 and its errata. - */ uint16_t odp_chksum_ones_comp16(const void *p, uint32_t len) { - uint32_t sum = 0; - const uint16_t *data = p; - - while (len > 1) { - sum += *data++; - len -= 2; - } - - /* Add left-over byte, if any */ - if (len > 0) { - uint16_t left_over = 0; - - *(uint8_t *)&left_over = *(const uint8_t *)data; - sum += left_over; - } - - /* Fold 32-bit sum to 16 bits */ - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - return sum; + return chksum_finalize(chksum_partial(p, len, 0)); } -- cgit v1.2.3 From 3bedbf06634aa40f5fd19351557f6004d20d0b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Tue, 22 Dec 2020 16:36:57 +0200 Subject: linux-gen: packet: use new software checksum functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use new software checksum functions and clean up the related code. Signed-off-by: Jere Leppänen Reviewed-by: Petri Savolainen --- platform/linux-generic/odp_packet.c | 192 ++++++++++++------------------------ 1 file changed, 64 insertions(+), 128 deletions(-) diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c index 2fe7fe67d..752ff8416 100644 --- a/platform/linux-generic/odp_packet.c +++ b/platform/linux-generic/odp_packet.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1785,73 +1786,12 @@ int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt) return dst_uarea_size < src_uarea_size; } -/* Simple implementation of ones complement sum. - * Based on RFC1071 and its errata. - */ -typedef union { - uint16_t w; - uint8_t b[2]; -} swap_buf_t; - -static uint32_t segment_sum16_32(const uint8_t *p, - uint32_t len, - uint32_t offset) - +static uint64_t packet_sum_partial(odp_packet_hdr_t *pkt_hdr, + uint32_t l3_offset, + uint32_t offset, + uint32_t len) { - uint32_t sum = 0; - - /* Include second part of 16-bit short word split between segments */ - if (len > 0 && (offset % 2)) { - swap_buf_t sw; - - sw.b[0] = 0; - sw.b[1] = *p++; - sum = sw.w; - len--; - } - - /* - * If pointer is 16-bit aligned, we can do fast path calculation. - * If it is not, we sum hi and lo bytes separately and then sum them. - */ - if ((uintptr_t)p % 2) { - uint32_t sum1 = 0, sum2 = 0; - - while (len > 1) { - sum1 += *p++; - sum2 += *p++; - len -= 2; - } -#if (ODP_BYTE_ORDER == ODP_BIG_ENDIAN) - sum += sum2 + (sum1 << 8); -#else - sum += sum1 + (sum2 << 8); -#endif - } else { - while (len > 1) { - sum += *(const uint16_t *)(uintptr_t)p; - p += 2; - len -= 2; - } - } - - /* Add left-over byte, if any */ - if (len > 0) { - swap_buf_t sw; - - sw.b[0] = *p; - sw.b[1] = 0; - sum += sw.w; - } - - return sum; -} - -static uint32_t packet_sum16_32(odp_packet_hdr_t *pkt_hdr, - uint32_t offset, - uint32_t len) -{ - uint32_t sum = 0; + uint64_t sum = 0; if (offset + len > pkt_hdr->frame_len) return 0; @@ -1863,7 +1803,7 @@ static uint32_t packet_sum16_32(odp_packet_hdr_t *pkt_hdr, if (seglen > len) seglen = len; - sum += segment_sum16_32(mapaddr, seglen, offset); + sum += chksum_partial(mapaddr, seglen, offset - l3_offset); len -= seglen; offset += seglen; } @@ -1871,20 +1811,14 @@ static uint32_t packet_sum16_32(odp_packet_hdr_t *pkt_hdr, return sum; } -static uint16_t packet_sum_ones_comp16(odp_packet_hdr_t *pkt_hdr, - uint32_t offset, - uint32_t len, - uint32_t l4_part_sum) +static inline uint16_t packet_sum(odp_packet_hdr_t *pkt_hdr, + uint32_t l3_offset, + uint32_t offset, + uint32_t len, + uint64_t sum) { - uint32_t sum = l4_part_sum; - - sum += packet_sum16_32(pkt_hdr, offset, len); - - /* Not more than two additions */ - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - - return sum; + sum += packet_sum_partial(pkt_hdr, l3_offset, offset, len); + return chksum_finalize(sum); } static uint32_t packet_sum_crc32c(odp_packet_hdr_t *pkt_hdr, @@ -1999,7 +1933,7 @@ error: static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, uint32_t *offset, uint32_t frame_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_ipv4hdr_t *ipv4 = (const _odp_ipv4hdr_t *)*parseptr; uint32_t dstaddr = odp_be_to_cpu_32(ipv4->dst_addr); @@ -2017,7 +1951,7 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, if (chksums.chksum.ipv4) { prs->input_flags.l3_chksum_done = 1; - if (odp_chksum_ones_comp16(ipv4, ihl * 4) != 0xffff) { + if (chksum_finalize(chksum_partial(ipv4, ihl * 4, 0)) != 0xffff) { prs->flags.ip_err = 1; prs->flags.l3_chksum_err = 1; return 0; @@ -2028,8 +1962,8 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, *parseptr += ihl * 4; if (chksums.chksum.udp || chksums.chksum.tcp) - *l4_part_sum = segment_sum16_32((const uint8_t *)&ipv4->src_addr, - 2 * _ODP_IPV4ADDR_LEN, 0); + *l4_part_sum = chksum_partial((const uint8_t *)&ipv4->src_addr, + 2 * _ODP_IPV4ADDR_LEN, 0); if (odp_unlikely(ihl > _ODP_IPV4HDR_IHL_MIN)) prs->input_flags.ipopt = 1; @@ -2059,7 +1993,7 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, uint32_t *offset, uint32_t frame_len, uint32_t seg_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_ipv6hdr_t *ipv6 = (const _odp_ipv6hdr_t *)*parseptr; const _odp_ipv6hdr_ext_t *ipv6ext; @@ -2083,8 +2017,8 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, *parseptr += sizeof(_odp_ipv6hdr_t); if (chksums.chksum.udp || chksums.chksum.tcp) - *l4_part_sum = segment_sum16_32((const uint8_t *)&ipv6->src_addr, - 2 * _ODP_IPV6ADDR_LEN, 0); + *l4_part_sum = chksum_partial((const uint8_t *)&ipv6->src_addr, + 2 * _ODP_IPV6ADDR_LEN, 0); /* Skip past any IPv6 extension headers */ if (ipv6->next_hdr == _ODP_IPPROTO_HOPOPTS || @@ -2127,7 +2061,7 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr, uint16_t tcp_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_tcphdr_t *tcp = (const _odp_tcphdr_t *)*parseptr; uint32_t len = tcp->hl * 4; @@ -2153,7 +2087,7 @@ static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr, */ static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_udphdr_t *udp = (const _odp_udphdr_t *)*parseptr; uint32_t udplen = odp_be_to_cpu_16(udp->length); @@ -2200,7 +2134,7 @@ static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr, static inline void parse_sctp(packet_parser_t *prs, const uint8_t **parseptr, uint16_t sctp_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { if (odp_unlikely(sctp_len < sizeof(_odp_sctphdr_t))) { prs->flags.sctp_err = 1; @@ -2228,7 +2162,7 @@ int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr, uint32_t frame_len, uint32_t seg_len, int layer, uint16_t ethtype, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { uint8_t ip_proto; @@ -2341,7 +2275,7 @@ int _odp_packet_parse_common(packet_parser_t *prs, const uint8_t *ptr, uint32_t offset; uint16_t ethtype; const uint8_t *parseptr; - uint32_t l4_part_sum; + uint64_t l4_part_sum; parseptr = ptr; offset = 0; @@ -2378,7 +2312,7 @@ static inline int packet_ipv4_chksum(odp_packet_t pkt, if (odp_unlikely(res < 0)) return res; - *chksum = ~odp_chksum_ones_comp16(buf, nleft); + *chksum = ~chksum_finalize(chksum_partial(buf, nleft, 0)); return 0; } @@ -2426,7 +2360,7 @@ static int _odp_packet_tcp_udp_chksum_insert(odp_packet_t pkt, uint16_t proto) { odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); uint32_t zero = 0; - uint32_t sum; + uint64_t sum; uint16_t l3_ver; uint16_t chksum; uint32_t chksum_offset; @@ -2439,15 +2373,17 @@ static int _odp_packet_tcp_udp_chksum_insert(odp_packet_t pkt, uint16_t proto) odp_packet_copy_to_mem(pkt, pkt_hdr->p.l3_offset, 2, &l3_ver); if (_ODP_IPV4HDR_VER(l3_ver) == _ODP_IPV4) - sum = packet_sum16_32(pkt_hdr, - pkt_hdr->p.l3_offset + - _ODP_IPV4ADDR_OFFSSET, - 2 * _ODP_IPV4ADDR_LEN); + sum = packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l3_offset + + _ODP_IPV4ADDR_OFFSSET, + 2 * _ODP_IPV4ADDR_LEN); else - sum = packet_sum16_32(pkt_hdr, - pkt_hdr->p.l3_offset + - _ODP_IPV6ADDR_OFFSSET, - 2 * _ODP_IPV6ADDR_LEN); + sum = packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l3_offset + + _ODP_IPV6ADDR_OFFSSET, + 2 * _ODP_IPV6ADDR_LEN); #if ODP_BYTE_ORDER == ODP_BIG_ENDIAN sum += proto; #else @@ -2459,24 +2395,22 @@ static int _odp_packet_tcp_udp_chksum_insert(odp_packet_t pkt, uint16_t proto) pkt_hdr->p.l4_offset); chksum_offset = pkt_hdr->p.l4_offset + _ODP_UDP_CSUM_OFFSET; } else { - sum += packet_sum16_32(pkt_hdr, - pkt_hdr->p.l4_offset + - _ODP_UDP_LEN_OFFSET, - 2); + sum += packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset + + _ODP_UDP_LEN_OFFSET, + 2); chksum_offset = pkt_hdr->p.l4_offset + _ODP_UDP_CSUM_OFFSET; } odp_packet_copy_from_mem(pkt, chksum_offset, 2, &zero); - sum += packet_sum16_32(pkt_hdr, - pkt_hdr->p.l4_offset, - pkt_hdr->frame_len - - pkt_hdr->p.l4_offset); - - /* Not more than two additions */ - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); + sum += packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset, + pkt_hdr->frame_len - + pkt_hdr->p.l4_offset); - chksum = ~sum; + chksum = ~chksum_finalize(sum); if (proto == _ODP_IPPROTO_UDP && chksum == 0) chksum = 0xffff; @@ -2538,18 +2472,19 @@ int _odp_packet_sctp_chksum_insert(odp_packet_t pkt) static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, odp_proto_chksums_t chksums, - uint32_t l4_part_sum) + uint64_t l4_part_sum) { /* UDP chksum == 0 case is covered in parse_udp() */ if (chksums.chksum.udp && pkt_hdr->p.input_flags.udp && !pkt_hdr->p.input_flags.ipfrag && !pkt_hdr->p.input_flags.udp_chksum_zero) { - uint16_t sum = ~packet_sum_ones_comp16(pkt_hdr, - pkt_hdr->p.l4_offset, - pkt_hdr->frame_len - - pkt_hdr->p.l4_offset, - l4_part_sum); + uint16_t sum = ~packet_sum(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset, + pkt_hdr->frame_len - + pkt_hdr->p.l4_offset, + l4_part_sum); pkt_hdr->p.input_flags.l4_chksum_done = 1; if (sum != 0) { @@ -2562,11 +2497,12 @@ static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, if (chksums.chksum.tcp && pkt_hdr->p.input_flags.tcp && !pkt_hdr->p.input_flags.ipfrag) { - uint16_t sum = ~packet_sum_ones_comp16(pkt_hdr, - pkt_hdr->p.l4_offset, - pkt_hdr->frame_len - - pkt_hdr->p.l4_offset, - l4_part_sum); + uint16_t sum = ~packet_sum(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset, + pkt_hdr->frame_len - + pkt_hdr->p.l4_offset, + l4_part_sum); pkt_hdr->p.input_flags.l4_chksum_done = 1; if (sum != 0) { @@ -2613,7 +2549,7 @@ int _odp_packet_parse_layer(odp_packet_hdr_t *pkt_hdr, const uint8_t *base = packet_data(pkt_hdr); uint32_t offset = 0; uint16_t ethtype; - uint32_t l4_part_sum = 0; + uint64_t l4_part_sum = 0; int rc; if (odp_unlikely(layer == ODP_PROTO_LAYER_NONE)) @@ -2649,7 +2585,7 @@ int odp_packet_parse(odp_packet_t pkt, uint32_t offset, odp_proto_layer_t layer = param->last_layer; int ret; uint16_t ethtype; - uint32_t l4_part_sum = 0; + uint64_t l4_part_sum = 0; if (proto == ODP_PROTO_NONE || layer == ODP_PROTO_LAYER_NONE) return -1; -- cgit v1.2.3 From 4e371d2e3d9bb0e3e2603b4bc3d7ceea321d0971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Fri, 5 Feb 2021 11:56:45 +0200 Subject: validation: chksum: add pseudorandom data test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test odp_chksum_ones_comp16() with pseudorandom data using different lengths and alignments. Signed-off-by: Jere Leppänen Reviewed-by: Petri Savolainen --- test/validation/api/chksum/chksum.c | 80 +++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/test/validation/api/chksum/chksum.c b/test/validation/api/chksum/chksum.c index ce905c04b..d6ff54b10 100644 --- a/test/validation/api/chksum/chksum.c +++ b/test/validation/api/chksum/chksum.c @@ -313,10 +313,90 @@ static void chksum_ones_complement_udp_long(void) CU_ASSERT(res == UDP_LONG_CHKSUM); } +static uint16_t chksum_rfc1071(const void *p, uint32_t len) +{ + uint32_t sum = 0; + const uint16_t *data = p; + + while (len > 1) { + sum += *data++; + len -= 2; + } + + /* Add left-over byte, if any */ + if (len > 0) { + uint16_t left_over = 0; + + *(uint8_t *)&left_over = *(const uint8_t *)data; + sum += left_over; + } + + /* Fold 32-bit sum to 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return sum; +} + +/* + * 64-bit KISS RNGs + * George Marsaglia + * https://www.thecodingforums.com/threads/64-bit-kiss-rngs.673657 + */ + +static unsigned long long x = 1234567890987654321ULL, c = 123456123456123456ULL, + y = 362436362436362436ULL, z = 1066149217761810ULL, t; + +#define MWC (t = (x << 58) + c, c = (x >> 6), x += t, c += (x < t), x) +#define XSH (y ^= (y << 13), y ^= (y >> 17), y ^= (y << 43)) +#define CNG (z = 6906969069LL * z + 1234567) +#define KISS (MWC + XSH + CNG) + +/* + * Test with pseudorandom data and different data lengths and alignments. + */ +static void chksum_ones_complement_pseudorandom(void) +{ + const int size = 32 * 1024; + const unsigned long page = 4096; + /* Allocate some extra pages for alignment and length. */ + uint8_t *buf = (uint8_t *)malloc(size + page * 4); + uint8_t *data = (uint8_t *)(((uintptr_t)buf + (page - 1)) & ~(page - 1)); + + for (int i = 0; i < (size + (int)page * 3) / 8; i++) + ((uint64_t *)(uintptr_t)data)[i] = KISS; + + /* Test data lengths from 1 to more than 9000 bytes. */ + for (int len = 1; len < 10000; len++) { + /* + * To avoid spending too much time on long data, the number of + * rounds goes down as data length goes up. + */ + int rounds = 1000000000 / (len * len + 1000000); + + for (int i = 0; i < rounds; i++) { + /* Align p to two bytes. */ + uint8_t *p = data + (KISS & (size - 1) & ~1UL); + /* + * Generate some fresh random bits at the start of the + * data to be checksummed. + */ + uint64_t rnd = KISS; + + memcpy(p, &rnd, sizeof(rnd)); + CU_ASSERT(chksum_rfc1071(p, len) == + odp_chksum_ones_comp16(p, len)); + } + } + + free(buf); +} + odp_testinfo_t chksum_suite[] = { ODP_TEST_INFO(chksum_ones_complement_ip), ODP_TEST_INFO(chksum_ones_complement_udp), ODP_TEST_INFO(chksum_ones_complement_udp_long), + ODP_TEST_INFO(chksum_ones_complement_pseudorandom), ODP_TEST_INFO_NULL, }; -- cgit v1.2.3 From d2d618bb91812890c8c5e11583cdad506f6d2beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Fri, 5 Feb 2021 12:40:39 +0200 Subject: validation: chksum: add test for very long data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test odp_chksum_ones_comp16() with very long data with almost all bits set, using different lengths and alignments. Signed-off-by: Jere Leppänen Reviewed-by: Petri Savolainen --- test/validation/api/chksum/chksum.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/validation/api/chksum/chksum.c b/test/validation/api/chksum/chksum.c index d6ff54b10..86306ab0b 100644 --- a/test/validation/api/chksum/chksum.c +++ b/test/validation/api/chksum/chksum.c @@ -392,11 +392,43 @@ static void chksum_ones_complement_pseudorandom(void) free(buf); } +/* + * Test with very long data with most of the bits set. The idea is to + * maximize the number of carries. + */ +static void chksum_ones_complement_very_long(void) +{ + const int size = 64 * 1024; + const unsigned long page = 4096; + /* Allocate two extra pages for alignment. */ + uint8_t *buf = (uint8_t *)malloc(size + page * 2); + uint8_t *data = (uint8_t *)(((uintptr_t)buf + (page - 1)) & ~(page - 1)); + + /* Start with all bits set. */ + memset(data, 0xff, size + page); + + for (int i = 0; i < 100; i++) { + for (int len = size - 8; len <= size; len++) { + /* Alignment 0, 2, 4, 6, 8. */ + for (int a = 0; a <= 8; a += 2) + CU_ASSERT(chksum_rfc1071(data + a, len) == + odp_chksum_ones_comp16(data + a, len)); + } + + /* Turn off some random bits in the data. */ + uint64_t rnd = KISS; + ((uint8_t *)data)[rnd & (size - 1)] &= (rnd >> 32) & 0xff; + } + + free(buf); +} + odp_testinfo_t chksum_suite[] = { ODP_TEST_INFO(chksum_ones_complement_ip), ODP_TEST_INFO(chksum_ones_complement_udp), ODP_TEST_INFO(chksum_ones_complement_udp_long), ODP_TEST_INFO(chksum_ones_complement_pseudorandom), + ODP_TEST_INFO(chksum_ones_complement_very_long), ODP_TEST_INFO_NULL, }; -- cgit v1.2.3 From 9335ef44ea8597358bdab397d038ecc90573ebfa Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 11 Feb 2021 14:16:37 +0200 Subject: linux-gen: timer: use atomic u32 functions from API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use u32 atomic API functions instead of internal functions. API functions are inlined, so there's no performance degradation. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen --- platform/linux-generic/odp_timer.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index ce33c6787..15f2af0d5 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -504,13 +505,12 @@ static inline odp_timer_t timer_alloc(timer_pool_t *tp, tp->first_free = get_next_free(tim); /* Initialize timer */ timer_init(tim, &tp->tick_buf[idx], queue, user_ptr); - if (odp_unlikely(tp->num_alloc > - odp_atomic_load_u32(&tp->high_wm))) + if (odp_unlikely(tp->num_alloc > odp_atomic_load_u32(&tp->high_wm))) { /* Update high_wm last with release model to * ensure timer initialization is visible */ - _odp_atomic_u32_store_mm(&tp->high_wm, - tp->num_alloc, - _ODP_MEMMODEL_RLS); + odp_atomic_store_rel_u32(&tp->high_wm, tp->num_alloc); + } + hdl = tp_idx_to_handle(tp, idx); /* Add timer to queue */ _odp_queue_fn->timer_add(queue); @@ -888,8 +888,7 @@ static inline void timer_expire(timer_pool_t *tp, uint32_t idx, uint64_t tick) static inline void timer_pool_scan(timer_pool_t *tp, uint64_t tick) { tick_buf_t *array = &tp->tick_buf[0]; - uint32_t high_wm = _odp_atomic_u32_load_mm(&tp->high_wm, - _ODP_MEMMODEL_ACQ); + uint32_t high_wm = odp_atomic_load_acq_u32(&tp->high_wm); uint32_t i; ODP_ASSERT(high_wm <= tp->param.num_timers); -- cgit v1.2.3 From 43817f1532bcccdd94f4f48f1d0be317e9d8c028 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 11 Feb 2021 14:32:56 +0200 Subject: linux-gen: timer: use atomic u64 load/store from API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use atomic u64 load/store API functions instead of internal functions. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen --- platform/linux-generic/odp_timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 15f2af0d5..1a96c3e1c 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -201,7 +201,7 @@ static void timer_init(_odp_timer_t *tim, #if __GCC_ATOMIC_LLONG_LOCK_FREE < 2 tb->exp_tck.v = TMO_INACTIVE; #else - _odp_atomic_u64_store_mm(&tb->exp_tck, TMO_INACTIVE, _ODP_MEMMODEL_RLS); + odp_atomic_store_rel_u64(&tb->exp_tck, TMO_INACTIVE); #endif } @@ -806,7 +806,7 @@ static inline void timer_expire(timer_pool_t *tp, uint32_t idx, uint64_t tick) uint64_t exp_tck; #ifdef ODP_ATOMIC_U128 /* Atomic re-read for correctness */ - exp_tck = _odp_atomic_u64_load_mm(&tb->exp_tck, _ODP_MEMMODEL_RLX); + exp_tck = odp_atomic_load_u64(&tb->exp_tck); /* Re-check exp_tck */ if (odp_likely(exp_tck <= tick)) { /* Attempt to grab timeout buffer, replace with inactive timer -- cgit v1.2.3 From 48fe4ea031d9a027aeea6c931746438b5dcc9091 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 11 Feb 2021 15:06:46 +0200 Subject: linux-gen: timer: use atomic u64 cas/xchg from API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use atomic u64 CAS and exchange API functions instead of internal functions. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen --- platform/linux-generic/odp_timer.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 1a96c3e1c..bdff3ab9b 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -602,8 +602,8 @@ static bool timer_reset(uint32_t idx, uint64_t abs_tck, odp_buffer_t *tmo_buf, uint64_t old; /* Swap in new expiration tick, get back old tick which * will indicate active/inactive timer state */ - old = _odp_atomic_u64_xchg_mm(&tb->exp_tck, abs_tck, - _ODP_MEMMODEL_RLX); + old = odp_atomic_xchg_u64(&tb->exp_tck, abs_tck); + if ((old & TMO_INACTIVE) != 0) { /* Timer was inactive (cancelled or expired), * we can't reset a timer without a timeout buffer. @@ -615,12 +615,7 @@ static bool timer_reset(uint32_t idx, uint64_t abs_tck, odp_buffer_t *tmo_buf, * reset or cancelled the timer. Without any * synchronization between the threads, we have a * data race and the behavior is undefined */ - (void)_odp_atomic_u64_cmp_xchg_strong_mm( - &tb->exp_tck, - &abs_tck, - old, - _ODP_MEMMODEL_RLX, - _ODP_MEMMODEL_RLX); + (void)odp_atomic_cas_u64(&tb->exp_tck, &abs_tck, old); success = false; } #else /* Target supports neither 128-bit nor 64-bit CAS => use lock */ -- cgit v1.2.3 From 869a04c389ceeb25e8a854b890e0af2d26382b2a Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 11 Feb 2021 14:26:10 +0200 Subject: linux-gen: atomic: remove unused internal functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused functions from atomic internal header. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen --- .../linux-generic/include/odp_atomic_internal.h | 564 +-------------------- 1 file changed, 2 insertions(+), 562 deletions(-) diff --git a/platform/linux-generic/include/odp_atomic_internal.h b/platform/linux-generic/include/odp_atomic_internal.h index 5ab4a89af..81280b1fa 100644 --- a/platform/linux-generic/include/odp_atomic_internal.h +++ b/platform/linux-generic/include/odp_atomic_internal.h @@ -26,13 +26,6 @@ extern "C" { #endif -/** - * Pointer atomic type - */ -typedef struct ODP_ALIGNED(sizeof(void *)) { - void *v; /**< Actual storage for the atomic variable */ -} _odp_atomic_ptr_t; - /** * Atomic flag (boolean) type * @Note this is not the same as a plain boolean type. @@ -58,562 +51,9 @@ typedef enum { _ODP_MEMMODEL_RLS = __ATOMIC_RELEASE, /** Acquire&release memory ordering, synchronize with acquire loads and release * stores in another (one other) thread */ - _ODP_MEMMODEL_ACQ_RLS = __ATOMIC_ACQ_REL, -/** Sequential consistent memory ordering, synchronize with acquire loads and - * release stores in all threads */ - _ODP_MEMMODEL_SC = __ATOMIC_SEQ_CST -} _odp_memmodel_t; - -/***************************************************************************** - * Operations on 32-bit atomics - * _odp_atomic_u32_load_mm - return current value - * _odp_atomic_u32_store_mm - no return value - * _odp_atomic_u32_xchg_mm - return old value - * _odp_atomic_u32_cmp_xchg_strong_mm - return bool - * _odp_atomic_u32_fetch_add_mm - return old value - * _odp_atomic_u32_add_mm - no return value - * _odp_atomic_u32_fetch_sub_mm - return old value - * _odp_atomic_u32_sub_mm - no return value - *****************************************************************************/ - -/** - * Atomic load of 32-bit atomic variable - * - * @param atom Pointer to a 32-bit atomic variable - * @param mmodel Memory ordering associated with the load operation - * - * @return Value of the variable - */ -static inline uint32_t _odp_atomic_u32_load_mm(const odp_atomic_u32_t *atom, - _odp_memmodel_t mmodel) -{ - return __atomic_load_n(&atom->v, mmodel); -} - -/** - * Atomic store to 32-bit atomic variable - * - * @param[out] atom Pointer to a 32-bit atomic variable - * @param val Value to store in the atomic variable - * @param mmodel Memory order associated with the store operation - */ -static inline void _odp_atomic_u32_store_mm(odp_atomic_u32_t *atom, - uint32_t val, - _odp_memmodel_t mmodel) -{ - __atomic_store_n(&atom->v, val, mmodel); -} - -/** - * Atomic exchange (swap) of 32-bit atomic variable - * - * @param[in,out] atom Pointer to a 32-bit atomic variable - * @param val New value to store in the atomic variable - * @param mmodel Memory order associated with the exchange operation - * - * @return Old value of the variable - */ -static inline uint32_t _odp_atomic_u32_xchg_mm(odp_atomic_u32_t *atom, - uint32_t val, - _odp_memmodel_t mmodel) - -{ - return __atomic_exchange_n(&atom->v, val, mmodel); -} - -/** - * Atomic compare and exchange (swap) of 32-bit atomic variable - * "Strong" semantics, will not fail spuriously. - * - * @param[in,out] atom Pointer to a 32-bit atomic variable - * @param[in,out] exp Pointer to expected value (updated on failure) - * @param val New value to write - * @param success Memory order associated with a successful compare-and-swap - * operation - * @param failure Memory order associated with a failed compare-and-swap - * operation - * - * @retval 1 exchange successul - * @retval 0 exchange failed and '*exp' updated with current value - */ -static inline int _odp_atomic_u32_cmp_xchg_strong_mm(odp_atomic_u32_t *atom, - uint32_t *exp, - uint32_t val, - _odp_memmodel_t success, - _odp_memmodel_t failure) -{ - return __atomic_compare_exchange_n(&atom->v, exp, val, - false/*strong*/, success, failure); -} - -/** - * Atomic fetch and add of 32-bit atomic variable - * - * @param[in,out] atom Pointer to a 32-bit atomic variable - * @param val Value to add to the atomic variable - * @param mmodel Memory order associated with the add operation - * - * @return Value of the atomic variable before the addition - */ -static inline uint32_t _odp_atomic_u32_fetch_add_mm(odp_atomic_u32_t *atom, - uint32_t val, - _odp_memmodel_t mmodel) -{ - return __atomic_fetch_add(&atom->v, val, mmodel); -} - -/** - * Atomic add of 32-bit atomic variable - * - * @param[in,out] atom Pointer to a 32-bit atomic variable - * @param val Value to add to the atomic variable - * @param mmodel Memory order associated with the add operation - */ -static inline void _odp_atomic_u32_add_mm(odp_atomic_u32_t *atom, uint32_t val, - _odp_memmodel_t mmodel) + _ODP_MEMMODEL_ACQ_RLS = __ATOMIC_ACQ_REL -{ - (void)__atomic_fetch_add(&atom->v, val, mmodel); -} - -/** - * Atomic fetch and subtract of 32-bit atomic variable - * - * @param[in,out] atom Pointer to a 32-bit atomic variable - * @param val Value to subtract from the atomic variable - * @param mmodel Memory order associated with the subtract operation - * - * @return Value of the atomic variable before the subtraction - */ -static inline uint32_t _odp_atomic_u32_fetch_sub_mm(odp_atomic_u32_t *atom, - uint32_t val, - _odp_memmodel_t mmodel) -{ - return __atomic_fetch_sub(&atom->v, val, mmodel); -} - -/** - * Atomic subtract of 32-bit atomic variable - * - * @param[in,out] atom Pointer to a 32-bit atomic variable - * @param val Value to subtract from the atomic variable - * @param mmodel Memory order associated with the subtract operation - */ -static inline void _odp_atomic_u32_sub_mm(odp_atomic_u32_t *atom, uint32_t val, - _odp_memmodel_t mmodel) - -{ - (void)__atomic_fetch_sub(&atom->v, val, mmodel); -} - -/***************************************************************************** - * Operations on 64-bit atomics - * _odp_atomic_u64_load_mm - return current value - * _odp_atomic_u64_store_mm - no return value - * _odp_atomic_u64_xchg_mm - return old value - * _odp_atomic_u64_cmp_xchg_strong_mm - return bool - * _odp_atomic_u64_fetch_add_mm - return old value - * _odp_atomic_u64_add_mm - no return value - * _odp_atomic_u64_fetch_sub_mm - return old value - * _odp_atomic_u64_sub_mm - no return value - *****************************************************************************/ - -/* Check if the compiler support lock-less atomic operations on 64-bit types */ -#ifdef ODP_ATOMIC_U64_LOCK -/** - * @internal - * Helper macro for lock-based atomic operations on 64-bit integers - * @param[in,out] atom Pointer to the 64-bit atomic variable - * @param expr Expression used update the variable. - * @param mm Memory order to use. - * @return The old value of the variable. - */ -#define ATOMIC_OP_MM(atom, expr, mm) \ -({ \ - uint64_t old_val; \ - /* Loop while lock is already taken, stop when lock becomes clear */ \ - while (__atomic_test_and_set(&(atom)->lock, \ - (mm) == _ODP_MEMMODEL_SC ? \ - __ATOMIC_SEQ_CST : __ATOMIC_ACQUIRE)) \ - (void)0; \ - old_val = (atom)->v; \ - (expr); /* Perform whatever update is desired */ \ - __atomic_clear(&(atom)->lock, \ - (mm) == _ODP_MEMMODEL_SC ? \ - __ATOMIC_SEQ_CST : __ATOMIC_RELEASE); \ - old_val; /* Return old value */ \ -}) - -/** - * Atomic load of 64-bit atomic variable - * - * @param atom Pointer to a 64-bit atomic variable - * @param mmodel Memory order associated with the load operation - * - * @return Value of the variable - */ -static inline uint64_t _odp_atomic_u64_load_mm(odp_atomic_u64_t *atom, - _odp_memmodel_t mmodel) -{ - return ATOMIC_OP_MM(atom, (void)0, mmodel); -} - -/** - * Atomic store to 64-bit atomic variable - * - * @param[out] atom Pointer to a 64-bit atomic variable - * @param val Value to write to the atomic variable - * @param mmodel Memory order associated with the store operation - */ -static inline void _odp_atomic_u64_store_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) -{ - (void)ATOMIC_OP_MM(atom, atom->v = val, mmodel); -} - -/** - * Atomic exchange (swap) of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val New value to write to the atomic variable - * @param mmodel Memory order associated with the exchange operation - * - * @return Old value of variable - */ -static inline uint64_t _odp_atomic_u64_xchg_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) - -{ - return ATOMIC_OP_MM(atom, atom->v = val, mmodel); -} - -/** - * Atomic compare and exchange (swap) of 64-bit atomic variable - * "Strong" semantics, will not fail spuriously. - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param[in,out] exp Pointer to expected value (updated on failure) - * @param val New value to write - * @param success Memory order associated with a successful compare-and-swap - * operation - * @param failure Memory order associated with a failed compare-and-swap - * operation - * - * @retval 1 exchange successful - * @retval 0 exchange failed and '*exp' updated with current value - */ -static inline int _odp_atomic_u64_cmp_xchg_strong_mm(odp_atomic_u64_t *atom, - uint64_t *exp, - uint64_t val, - _odp_memmodel_t success, - _odp_memmodel_t failure) -{ - /* Possibly we are a bit pessimistic with the memory models */ - odp_bool_t ret_succ; - /* Loop while lock is already taken, stop when lock becomes clear */ - while (__atomic_test_and_set(&(atom)->lock, - (success) == _ODP_MEMMODEL_SC ? - __ATOMIC_SEQ_CST : __ATOMIC_ACQUIRE)) - (void)0; - if (atom->v == *exp) { - atom->v = val; - ret_succ = 1; - } else { - *exp = atom->v; - ret_succ = 0; - } - __atomic_clear(&(atom)->lock, - (ret_succ ? success : failure) == _ODP_MEMMODEL_SC ? - __ATOMIC_SEQ_CST : __ATOMIC_RELEASE); - return ret_succ; -} - -/** - * Atomic fetch and add of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to add to the atomic variable - * @param mmodel Memory order associated with the add operation - * - * @return Value of the atomic variable before the addition - */ -static inline uint64_t _odp_atomic_u64_fetch_add_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) -{ - return ATOMIC_OP_MM(atom, atom->v += val, mmodel); -} - -/** - * Atomic add of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to add to the atomic variable - * @param mmodel Memory order associated with the add operation. - */ -static inline void _odp_atomic_u64_add_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) - -{ - (void)ATOMIC_OP_MM(atom, atom->v += val, mmodel); -} - -/** - * Atomic fetch and subtract of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to subtract from the atomic variable - * @param mmodel Memory order associated with the subtract operation - * - * @return Value of the atomic variable before the subtraction - */ -static inline uint64_t _odp_atomic_u64_fetch_sub_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) -{ - return ATOMIC_OP_MM(atom, atom->v -= val, mmodel); -} - -/** - * Atomic subtract of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to subtract from the atomic variable - * @param mmodel Memory order associated with the subtract operation - */ -static inline void _odp_atomic_u64_sub_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) - -{ - (void)ATOMIC_OP_MM(atom, atom->v -= val, mmodel); -} - -#undef ATOMIC_OP_MM - -#else /* ! ODP_ATOMIC_U64_LOCK */ - -/** - * Atomic load of 64-bit atomic variable - * - * @param atom Pointer to a 64-bit atomic variable - * @param mmodel Memory order associated with the load operation - * - * @return Value of the variable - */ -static inline uint64_t _odp_atomic_u64_load_mm(odp_atomic_u64_t *atom, - _odp_memmodel_t mmodel) -{ - return __atomic_load_n(&atom->v, mmodel); -} - -/** - * Atomic store to 64-bit atomic variable - * - * @param[out] atom Pointer to a 64-bit atomic variable - * @param val Value to write to the atomic variable - * @param mmodel Memory order associated with the store operation - */ -static inline void _odp_atomic_u64_store_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) -{ - __atomic_store_n(&atom->v, val, mmodel); -} - -/** - * Atomic exchange (swap) of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val New value to write to the atomic variable - * @param mmodel Memory order associated with the exchange operation - * - * @return Old value of variable - */ -static inline uint64_t _odp_atomic_u64_xchg_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) - -{ - return __atomic_exchange_n(&atom->v, val, mmodel); -} - -/** - * Atomic compare and exchange (swap) of 64-bit atomic variable - * "Strong" semantics, will not fail spuriously. - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param[in,out] exp Pointer to expected value (updated on failure) - * @param val New value to write - * @param success Memory order associated with a successful compare-and-swap - * operation - * @param failure Memory order associated with a failed compare-and-swap - * operation - * - * @retval 1 exchange successful - * @retval 0 exchange failed and '*exp' updated with current value - */ -static inline int _odp_atomic_u64_cmp_xchg_strong_mm(odp_atomic_u64_t *atom, - uint64_t *exp, - uint64_t val, - _odp_memmodel_t success, - _odp_memmodel_t failure) -{ - return __atomic_compare_exchange_n(&atom->v, exp, val, - false/*strong*/, success, failure); -} - -/** - * Atomic fetch and add of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to add to the atomic variable - * @param mmodel Memory order associated with the add operation - * - * @return Value of the atomic variable before the addition - */ -static inline uint64_t _odp_atomic_u64_fetch_add_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) -{ - return __atomic_fetch_add(&atom->v, val, mmodel); -} - -/** - * Atomic add of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to add to the atomic variable - * @param mmodel Memory order associated with the add operation. - */ -static inline void _odp_atomic_u64_add_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) - -{ - (void)__atomic_fetch_add(&atom->v, val, mmodel); -} - -/** - * Atomic fetch and subtract of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to subtract from the atomic variable - * @param mmodel Memory order associated with the subtract operation - * - * @return Value of the atomic variable before the subtraction - */ -static inline uint64_t _odp_atomic_u64_fetch_sub_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) -{ - return __atomic_fetch_sub(&atom->v, val, mmodel); -} - -/** - * Atomic subtract of 64-bit atomic variable - * - * @param[in,out] atom Pointer to a 64-bit atomic variable - * @param val Value to subtract from the atomic variable - * @param mmodel Memory order associated with the subtract operation - */ -static inline void _odp_atomic_u64_sub_mm(odp_atomic_u64_t *atom, - uint64_t val, - _odp_memmodel_t mmodel) - -{ - (void)__atomic_fetch_sub(&atom->v, val, mmodel); -} - -#endif /* ! ODP_ATOMIC_U64_LOCK */ - -/***************************************************************************** - * Operations on pointer atomics - * _odp_atomic_ptr_init - no return value - * _odp_atomic_ptr_load - return current value - * _odp_atomic_ptr_store - no return value - * _odp_atomic_ptr_xchg - return old value - *****************************************************************************/ - -/** - * Initialization of pointer atomic variable - * - * @param[out] atom Pointer to a pointer atomic variable - * @param val Value to initialize the variable with - */ -static inline void _odp_atomic_ptr_init(_odp_atomic_ptr_t *atom, void *val) -{ - __atomic_store_n(&atom->v, val, __ATOMIC_RELAXED); -} - -/** - * Atomic load of pointer atomic variable - * - * @param atom Pointer to a pointer atomic variable - * @param mmodel Memory order associated with the load operation - * - * @return Value of the variable - */ -static inline void *_odp_atomic_ptr_load(const _odp_atomic_ptr_t *atom, - _odp_memmodel_t mmodel) -{ - return __atomic_load_n(&atom->v, mmodel); -} - -/** - * Atomic store to pointer atomic variable - * - * @param[out] atom Pointer to a pointer atomic variable - * @param val Value to write to the atomic variable - * @param mmodel Memory order associated with the store operation - */ -static inline void _odp_atomic_ptr_store(_odp_atomic_ptr_t *atom, void *val, - _odp_memmodel_t mmodel) -{ - __atomic_store_n(&atom->v, val, mmodel); -} - -/** - * Atomic exchange (swap) of pointer atomic variable - * - * @param[in,out] atom Pointer to a pointer atomic variable - * @param val New value to write - * @param mmodel Memory order associated with the exchange operation - * - * @return Old value of variable - */ -static inline void *_odp_atomic_ptr_xchg(_odp_atomic_ptr_t *atom, void *val, - _odp_memmodel_t mmodel) -{ - return __atomic_exchange_n(&atom->v, val, mmodel); -} - -/** - * Atomic compare and exchange (swap) of pointer atomic variable - * "Strong" semantics, will not fail spuriously. - * - * @param[in,out] atom Pointer to a pointer atomic variable - * @param[in,out] exp Pointer to expected value (updated on failure) - * @param val New value to write - * @param success Memory order associated with a successful compare-and-swap - * operation - * @param failure Memory order associated with a failed compare-and-swap - * operation - * - * @retval 1 exchange successful - * @retval 0 exchange failed and '*exp' updated with current value - */ -static inline int _odp_atomic_ptr_cmp_xchg_strong(_odp_atomic_ptr_t *atom, - void **exp, void *val, - _odp_memmodel_t success, - _odp_memmodel_t failure) -{ - return __atomic_compare_exchange_n(&atom->v, exp, val, - false/*strong*/, success, failure); -} +} _odp_memmodel_t; /***************************************************************************** * Operations on flag atomics -- cgit v1.2.3 From 79ec1eb306f4e3e2a2d6ce42991c822c97fdb6e7 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 28 Jan 2021 15:38:48 +0200 Subject: example: tm: prevent redefinition of _GNU_SOURCE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent failure if _GNU_SOURCE has been already defined. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- example/traffic_mgmt/odp_traffic_mgmt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example/traffic_mgmt/odp_traffic_mgmt.c b/example/traffic_mgmt/odp_traffic_mgmt.c index c80e03bab..fba494853 100644 --- a/example/traffic_mgmt/odp_traffic_mgmt.c +++ b/example/traffic_mgmt/odp_traffic_mgmt.c @@ -6,7 +6,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include #include -- cgit v1.2.3 From f831e6453c9bfd2b66ec8e1d19667e8fe7101e24 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 11 Feb 2021 16:20:39 +0200 Subject: github_ci: update codecov action version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update Codecov GitHub Action to the latest version (v1.2.1). Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index b4ee0da4f..53b874998 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -208,7 +208,7 @@ jobs: if: ${{ failure() }} run: find . -name "*.trs" | xargs grep -l '^.test-result. FAIL' | while read trs ; do echo FAILURE detected at $trs; cat ${trs%%.trs}.log ; done - name: Upload to Codecov - uses: codecov/codecov-action@v1.0.15 + uses: codecov/codecov-action@v1.2.1 Run_distcheck: runs-on: ubuntu-18.04 -- cgit v1.2.3 From ad3fbe28b63eb69f99f956d5d2cfdec994ada5a3 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Thu, 11 Feb 2021 16:20:39 +0200 Subject: codecov: improve coverage calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean Codecov configuration syntax, run coverage calculation immediately, and ignore the external miniz library files. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- .codecov.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 4b3a723c9..d5eddbf7d 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,21 +1,19 @@ codecov: notify: - require_ci_to_pass: yes + require_ci_to_pass: no + wait_for_ci: no coverage: - precision: 3 + precision: 2 round: down - range: "50...75" + range: "70...100" status: project: default: - enabled: yes target: 70% threshold: 5% - patch: - default: - enabled: no - changes: no + patch: off + changes: off parsers: gcov: @@ -26,3 +24,6 @@ parsers: macro: no comment: false + +ignore: + - "platform/linux-generic/miniz" -- cgit v1.2.3 From 47aec3221dc02ed6821763f3dee865a072754cce Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 12 Feb 2021 14:25:14 +0200 Subject: linux-gen: sched: remove unnecessary pointer operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary pointer operations detected by a static code analyzer. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-generic/odp_schedule_basic.c | 2 +- platform/linux-generic/odp_schedule_sp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/linux-generic/odp_schedule_basic.c b/platform/linux-generic/odp_schedule_basic.c index 0396123f3..32a21442d 100644 --- a/platform/linux-generic/odp_schedule_basic.c +++ b/platform/linux-generic/odp_schedule_basic.c @@ -1633,7 +1633,7 @@ static int schedule_num_grps(void) static void schedule_get_config(schedule_config_t *config) { - *config = *(&sched->config_if); + *config = sched->config_if; }; static int schedule_capability(odp_schedule_capability_t *capa) diff --git a/platform/linux-generic/odp_schedule_sp.c b/platform/linux-generic/odp_schedule_sp.c index 90ba101cd..cad391ed4 100644 --- a/platform/linux-generic/odp_schedule_sp.c +++ b/platform/linux-generic/odp_schedule_sp.c @@ -1037,7 +1037,7 @@ static int schedule_capability(odp_schedule_capability_t *capa) static void get_config(schedule_config_t *config) { - *config = *(&sched_global->config_if); + *config = sched_global->config_if; }; /* Fill in scheduler interface */ -- cgit v1.2.3 From b1183d4554c34656da1c7b9ab710aa7c3840014c Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 12 Feb 2021 14:42:05 +0200 Subject: linux-gen: cls: fix memory access out-of-bounds warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix memory accesses out-of-bounds warning thrown by a static code analyzer. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-generic/odp_classification.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c index 5f452c598..bfa410b44 100644 --- a/platform/linux-generic/odp_classification.c +++ b/platform/linux-generic/odp_classification.c @@ -691,8 +691,7 @@ static int pmr_create_term(pmr_term_value_t *value, return -1; } - memset(&value->match.value, 0, MAX_PMR_TERM_SIZE); - memset(&value->match.mask, 0, MAX_PMR_TERM_SIZE); + memset(&value->match, 0, sizeof(value->match)); memcpy(&value->match.value, param->match.value, param->val_sz); memcpy(&value->match.mask, param->match.mask, param->val_sz); -- cgit v1.2.3 From e90c90b512badf2bddb8c2206d54d6191b6bad0e Mon Sep 17 00:00:00 2001 From: Ashwin Sekhar T K Date: Tue, 27 Oct 2020 11:56:41 +0530 Subject: test: cunit: add cunit run mode for immediate test suite exit on failure In existing test framework, all the tests in a test suite are always run irrespective of individual test failures. This patchset adds an option to run the test suites in a mode where a test suite gets killed on the first test failure. This mode can be activated by setting the environment variable ODP_CUNIT_FAIL_IMMEDIATE. In this mode, before the start of any test in a test suite, it checks for errors in previously ran tests and immediately triggers an exit if an error is detected. Signed-off-by: Ashwin Sekhar T K Reviewed-by: Matias Elo --- test/common/odp_cunit_common.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/test/common/odp_cunit_common.c b/test/common/odp_cunit_common.c index 25895d628..62418c356 100644 --- a/test/common/odp_cunit_common.c +++ b/test/common/odp_cunit_common.c @@ -1,5 +1,6 @@ /* Copyright (c) 2014-2018, Linaro Limited * Copyright (c) 2019, Nokia + * Copyright (c) 2021, Marvell * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -273,6 +274,39 @@ static int default_term_func(void) return odp_cunit_print_inactive(); } +static void _cunit_test_setup_func(void) +{ + CU_AllTestsCompleteMessageHandler all_test_comp_handler; + CU_SuiteCompleteMessageHandler suite_comp_handler; + CU_pFailureRecord failrec; + CU_pSuite suite; + + if (!getenv("ODP_CUNIT_FAIL_IMMEDIATE")) + return; + + if (CU_get_number_of_failure_records() == 0) + return; + + /* User wants the suite to fail immediately once a test hits an error */ + suite = CU_get_current_suite(); + failrec = CU_get_failure_list(); + + printf("Force aborting as a previous test failed\n"); + + /* Call the Cleanup functions before aborting */ + suite->pCleanupFunc(); + + suite_comp_handler = CU_get_suite_complete_handler(); + if (suite_comp_handler) + suite_comp_handler(suite, failrec); + + all_test_comp_handler = CU_get_all_test_complete_handler(); + if (all_test_comp_handler) + all_test_comp_handler(failrec); + + exit(EXIT_FAILURE); +} + /* * Register suites and tests with CUnit. * @@ -292,7 +326,9 @@ static int cunit_register_suites(odp_suiteinfo_t testsuites[]) if (sinfo->term_func) term_func = sinfo->term_func; - suite = CU_add_suite(sinfo->name, _cunit_suite_init, term_func); + suite = CU_add_suite_with_setup_and_teardown(sinfo->name, _cunit_suite_init, + term_func, _cunit_test_setup_func, + NULL); if (!suite) return CU_get_error(); -- cgit v1.2.3 From 431c9939bc3b87c995308d2aa4f22689ca158f56 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Mon, 15 Feb 2021 17:45:48 +0200 Subject: linux-gen: crc: unsigned integer with bitwise operators Make it explicit that unsigned integers are used with bitwise operators. Fixes static code checker complains about: "bitwise operators should not be applied to signed operands". Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- platform/linux-generic/odp_hash_crc_gen.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/platform/linux-generic/odp_hash_crc_gen.c b/platform/linux-generic/odp_hash_crc_gen.c index 93ebe0e95..109d15420 100644 --- a/platform/linux-generic/odp_hash_crc_gen.c +++ b/platform/linux-generic/odp_hash_crc_gen.c @@ -66,15 +66,15 @@ static inline uint8_t reflect_u8(uint8_t byte) { uint8_t u8[8]; - u8[0] = (byte & (0x1 << 7)) >> 7; - u8[1] = (byte & (0x1 << 6)) >> 5; - u8[2] = (byte & (0x1 << 5)) >> 3; - u8[3] = (byte & (0x1 << 4)) >> 1; + u8[0] = (byte & (0x1u << 7)) >> 7; + u8[1] = (byte & (0x1u << 6)) >> 5; + u8[2] = (byte & (0x1u << 5)) >> 3; + u8[3] = (byte & (0x1u << 4)) >> 1; - u8[4] = (byte & (0x1 << 3)) << 1; - u8[5] = (byte & (0x1 << 2)) << 3; - u8[6] = (byte & (0x1 << 1)) << 5; - u8[7] = (byte & 0x1) << 7; + u8[4] = (byte & (0x1u << 3)) << 1; + u8[5] = (byte & (0x1u << 2)) << 3; + u8[6] = (byte & (0x1u << 1)) << 5; + u8[7] = (byte & 0x1u) << 7; return u8[0] | u8[1] | u8[2] | u8[3] | u8[4] | u8[5] | u8[6] | u8[7]; } @@ -84,10 +84,10 @@ static inline uint32_t reflect_u32(uint32_t u32) { uint8_t u8[4]; - u8[0] = reflect_u8((u32 & 0xff000000) >> 24); - u8[1] = reflect_u8((u32 & 0x00ff0000) >> 16); - u8[2] = reflect_u8((u32 & 0x0000ff00) >> 8); - u8[3] = reflect_u8(u32 & 0xff); + u8[0] = reflect_u8((u32 & 0xff000000u) >> 24); + u8[1] = reflect_u8((u32 & 0x00ff0000u) >> 16); + u8[2] = reflect_u8((u32 & 0x0000ff00u) >> 8); + u8[3] = reflect_u8(u32 & 0xffu); return (u8[3] << 24) | (u8[2] << 16) | (u8[1] << 8) | u8[0]; } @@ -97,9 +97,9 @@ static inline uint32_t reflect_u24(uint32_t u32) { uint8_t u8[4]; - u8[0] = reflect_u8((u32 & 0xff0000) >> 16); - u8[1] = reflect_u8((u32 & 0x00ff00) >> 8); - u8[2] = reflect_u8(u32 & 0xff); + u8[0] = reflect_u8((u32 & 0xff0000u) >> 16); + u8[1] = reflect_u8((u32 & 0x00ff00u) >> 8); + u8[2] = reflect_u8(u32 & 0xffu); return (u8[2] << 16) | (u8[1] << 8) | u8[0]; } @@ -109,8 +109,8 @@ static inline uint32_t reflect_u16(uint32_t u32) { uint8_t u8[4]; - u8[0] = reflect_u8((u32 & 0xff00) >> 8); - u8[1] = reflect_u8(u32 & 0xff); + u8[0] = reflect_u8((u32 & 0xff00u) >> 8); + u8[1] = reflect_u8(u32 & 0xffu); return (u8[1] << 8) | u8[0]; } @@ -128,8 +128,8 @@ static inline void crc_table_gen(uint32_t poly, int reflect, int width) crc_table->reflect = reflect; shift = width - 8; - mask = 0xffffffff >> (32 - width); - msb = 0x1 << (width - 1); + mask = 0xffffffffu >> (32 - width); + msb = 0x1u << (width - 1); if (reflect) { if (width == 32) @@ -145,7 +145,7 @@ static inline void crc_table_gen(uint32_t poly, int reflect, int width) crc = i; for (bit = 0; bit < 8; bit++) { - if (crc & 0x1) + if (crc & 0x1u) crc = poly ^ (crc >> 1); else crc = crc >> 1; @@ -173,7 +173,7 @@ static inline uint32_t crc_calc(const uint8_t *data, uint32_t data_len, uint32_t mask; shift = width - 8; - mask = 0xffffffff >> (32 - width); + mask = 0xffffffffu >> (32 - width); crc = init_val; @@ -181,7 +181,7 @@ static inline uint32_t crc_calc(const uint8_t *data, uint32_t data_len, byte = data[i]; if (reflect) { - crc = crc_table->crc[(crc ^ byte) & 0xff] ^ (crc >> 8); + crc = crc_table->crc[(crc ^ byte) & 0xffu] ^ (crc >> 8); } else { crc = crc_table->crc[(crc >> shift) ^ byte] ^ (crc << 8); -- cgit v1.2.3 From 1c8d55eea13aaf3f66f1505cef1dbfac61c15e7b Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Mon, 15 Feb 2021 18:01:05 +0200 Subject: test: performance: skip duplicate test runs Scheduling performance and latency test applications are run multiple times during 'make check' with a different number of worker threads. Skip test runs if there are not enough CPU cores available. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- test/performance/odp_sched_latency_run.sh | 8 ++++++-- test/performance/odp_scheduling_run.sh | 17 ++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/test/performance/odp_sched_latency_run.sh b/test/performance/odp_sched_latency_run.sh index bcccd77a9..372fdb166 100755 --- a/test/performance/odp_sched_latency_run.sh +++ b/test/performance/odp_sched_latency_run.sh @@ -14,9 +14,13 @@ ALL=0 run() { echo odp_sched_latency_run starts requesting $1 worker threads - echo =============================================== + echo ========================================================= - $TEST_DIR/odp_sched_latency${EXEEXT} -c $1 || exit $? + if [ $(nproc) -lt $1 ]; then + echo "Not enough CPU cores. Skipping test." + else + $TEST_DIR/odp_sched_latency${EXEEXT} -c $1 || exit $? + fi } run 1 diff --git a/test/performance/odp_scheduling_run.sh b/test/performance/odp_scheduling_run.sh index 082dc4521..2b4281ee9 100755 --- a/test/performance/odp_scheduling_run.sh +++ b/test/performance/odp_scheduling_run.sh @@ -14,14 +14,17 @@ ALL=0 run() { echo odp_scheduling_run starts requesting $1 worker threads - echo =============================================== + echo ====================================================== - $TEST_DIR/odp_scheduling${EXEEXT} -c $1 - - RET_VAL=$? - if [ $RET_VAL -ne 0 ]; then - echo odp_scheduling FAILED - exit $RET_VAL + if [ $(nproc) -lt $1 ]; then + echo "Not enough CPU cores. Skipping test." + else + $TEST_DIR/odp_scheduling${EXEEXT} -c $1 + RET_VAL=$? + if [ $RET_VAL -ne 0 ]; then + echo odp_scheduling FAILED + exit $RET_VAL + fi fi } -- cgit v1.2.3 From 7796925ba39ef410f4eb512ad853d16e026b5f51 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Tue, 16 Feb 2021 10:53:06 +0200 Subject: example: timer_accuracy: add resolution in hertz option Added -R (--res_hz) option for passing resolution in hertz to timer pool parameters. Changed long name of -r option to "--res_ns". Signed-off-by: Petri Savolainen Reviewed-by: Matias Elo --- example/timer/odp_timer_accuracy.c | 66 +++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/example/timer/odp_timer_accuracy.c b/example/timer/odp_timer_accuracy.c index cd790a181..cafe362a7 100644 --- a/example/timer/odp_timer_accuracy.c +++ b/example/timer/odp_timer_accuracy.c @@ -1,5 +1,5 @@ /* Copyright (c) 2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -51,6 +51,7 @@ typedef struct test_global_t { struct { unsigned long long period_ns; unsigned long long res_ns; + unsigned long long res_hz; unsigned long long offset_ns; unsigned long long max_tmo_ns; unsigned long long num; @@ -89,7 +90,9 @@ static void print_usage(void) "\n" "OPTIONS:\n" " -p, --period Timeout period in nsec. Default: 200 msec\n" - " -r, --resolution Timeout resolution in nsec. Default: period / 10\n" + " -r, --res_ns Timeout resolution in nsec. Default: period / 10\n" + " -R, --res_hz Timeout resolution in hertz. Note: resolution can be set\n" + " either in nsec or hertz (not both). Default: 0\n" " -f, --first First timer offset in nsec. Default: 300 msec\n" " -x, --max_tmo Maximum timeout in nsec. When 0, max tmo is calculated from other options. Default: 0\n" " -n, --num Number of timeout periods. Default: 50\n" @@ -114,7 +117,8 @@ static int parse_options(int argc, char *argv[], test_global_t *test_global) int opt, long_index; const struct option longopts[] = { {"period", required_argument, NULL, 'p'}, - {"resolution", required_argument, NULL, 'r'}, + {"res_ns", required_argument, NULL, 'r'}, + {"res_hz", required_argument, NULL, 'R'}, {"first", required_argument, NULL, 'f'}, {"max_tmo", required_argument, NULL, 'x'}, {"num", required_argument, NULL, 'n'}, @@ -128,11 +132,12 @@ static int parse_options(int argc, char *argv[], test_global_t *test_global) {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; - const char *shortopts = "+p:r:f:x:n:b:g:m:o:e:s:ih"; + const char *shortopts = "+p:r:R:f:x:n:b:g:m:o:e:s:ih"; int ret = 0; test_global->opt.period_ns = 200 * ODP_TIME_MSEC_IN_NS; test_global->opt.res_ns = 0; + test_global->opt.res_hz = 0; test_global->opt.offset_ns = 300 * ODP_TIME_MSEC_IN_NS; test_global->opt.max_tmo_ns = 0; test_global->opt.num = 50; @@ -157,6 +162,9 @@ static int parse_options(int argc, char *argv[], test_global_t *test_global) case 'r': test_global->opt.res_ns = strtoull(optarg, NULL, 0); break; + case 'R': + test_global->opt.res_hz = strtoull(optarg, NULL, 0); + break; case 'f': test_global->opt.offset_ns = strtoull(optarg, NULL, 0); break; @@ -200,7 +208,8 @@ static int parse_options(int argc, char *argv[], test_global_t *test_global) } } - if (test_global->opt.res_ns == 0) + /* Default resolution */ + if (test_global->opt.res_ns == 0 && test_global->opt.res_hz == 0) test_global->opt.res_ns = test_global->opt.period_ns / 10; test_global->tot_timers = test_global->opt.num * test_global->opt.burst; @@ -224,7 +233,8 @@ static int start_timers(test_global_t *test_global) odp_queue_t queue; odp_queue_param_t queue_param; uint64_t tick, start_tick; - uint64_t period_ns, res_ns, start_ns, nsec, res_capa, offset_ns; + uint64_t period_ns, res_ns, res_hz, start_ns, nsec, offset_ns; + uint64_t max_res_ns, max_res_hz; odp_event_t event; odp_timeout_t timeout; odp_timer_set_t ret; @@ -298,22 +308,39 @@ static int start_timers(test_global_t *test_global) return -1; } - res_capa = timer_capa.highest_res_ns; + max_res_ns = timer_capa.max_res.res_ns; + max_res_hz = timer_capa.max_res.res_hz; offset_ns = test_global->opt.offset_ns; - res_ns = test_global->opt.res_ns; - if (res_ns < res_capa) { - printf("Resolution %" PRIu64 " nsec too high. " - "Highest resolution %" PRIu64 " nsec. " + if (test_global->opt.res_ns) { + res_ns = test_global->opt.res_ns; + res_hz = 0; + } else { + res_ns = 0; + res_hz = test_global->opt.res_hz; + } + + if (res_ns && res_ns < max_res_ns) { + printf("Resolution %" PRIu64 " nsec too high. Highest resolution %" PRIu64 " nsec. " "Default resolution is period / 10.\n\n", - res_ns, res_capa); + res_ns, max_res_ns); + return -1; + } + + if (res_hz && res_hz > max_res_hz) { + printf("Resolution %" PRIu64 " hz too high. Highest resolution %" PRIu64 " hz. " + "Default resolution is period / 10.\n\n", + res_hz, max_res_hz); return -1; } memset(&timer_param, 0, sizeof(odp_timer_pool_param_t)); - timer_param.res_ns = res_ns; + if (res_ns) + timer_param.res_ns = res_ns; + else + timer_param.res_hz = res_hz; if (mode == 0) { timer_param.min_tmo = offset_ns / 2; @@ -339,7 +366,8 @@ static int start_timers(test_global_t *test_global) printf("\nTest parameters:\n"); printf(" clock source: %i\n", test_global->opt.clk_src); - printf(" resolution capa: %" PRIu64 " nsec\n", res_capa); + printf(" max res nsec: %" PRIu64 "\n", max_res_ns); + printf(" max res hertz: %" PRIu64 "\n", max_res_hz); printf(" max timers capa: %" PRIu32 "\n", timer_capa.max_timers); printf(" mode: %i\n", mode); printf(" restart retries: %i\n", test_global->opt.early_retry); @@ -347,7 +375,10 @@ static int start_timers(test_global_t *test_global) printf(" log file: %s\n", test_global->filename); printf(" start offset: %" PRIu64 " nsec\n", offset_ns); printf(" period: %" PRIu64 " nsec\n", period_ns); - printf(" resolution: %" PRIu64 " nsec\n", timer_param.res_ns); + if (res_ns) + printf(" resolution: %" PRIu64 " nsec\n", res_ns); + else + printf(" resolution: %" PRIu64 " hz\n", res_hz); printf(" min timeout: %" PRIu64 " nsec\n", timer_param.min_tmo); printf(" max timeout: %" PRIu64 " nsec\n", timer_param.max_tmo); printf(" num timeout: %" PRIu64 "\n", num_tmo); @@ -494,11 +525,14 @@ static void print_stat(test_global_t *test_global) { uint64_t i; uint64_t tot_timers = test_global->tot_timers; - uint64_t res_ns = test_global->opt.res_ns; test_stat_t *stat = &test_global->stat; test_log_t *log = test_global->log; double ave_after = 0.0; double ave_before = 0.0; + double res_ns = test_global->opt.res_ns; + + if (test_global->opt.res_ns == 0) + res_ns = 1000000000.0 / test_global->opt.res_hz; if (stat->num_after) ave_after = (double)stat->nsec_after_sum / stat->num_after; -- cgit v1.2.3 From c70de9461221d30ec2dd95bb5ce8aa46e009d011 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 17 Feb 2021 17:27:43 +0200 Subject: validation: pktio: fix gcc -O1 build failures GCC 9.3.0 on Ubuntu 20.04 doesn't recognize CU_ASSERT_FATAL() correctly in -O1 optimization level causing build to fail on 'pktio[0] may be used uninitialized in this function' error. Fix this by initializing pktio array to zero. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- test/validation/api/pktio/pktio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/validation/api/pktio/pktio.c b/test/validation/api/pktio/pktio.c index 47320e2e8..3f8df07f3 100644 --- a/test/validation/api/pktio/pktio.c +++ b/test/validation/api/pktio/pktio.c @@ -1135,7 +1135,7 @@ static void pktio_test_recv_multi_event(void) static void pktio_test_recv_queue(void) { odp_pktio_t pktio_tx, pktio_rx; - odp_pktio_t pktio[MAX_NUM_IFACES]; + odp_pktio_t pktio[MAX_NUM_IFACES] = {0}; odp_pktio_capability_t capa; odp_pktin_queue_param_t in_queue_param; odp_pktout_queue_param_t out_queue_param; @@ -1247,7 +1247,7 @@ static void pktio_test_recv_queue(void) static void test_recv_tmo(recv_tmo_mode_e mode) { odp_pktio_t pktio_tx, pktio_rx; - odp_pktio_t pktio[MAX_NUM_IFACES]; + odp_pktio_t pktio[MAX_NUM_IFACES] = {0}; odp_pktio_capability_t capa; odp_pktin_queue_param_t in_queue_param; odp_pktout_queue_t pktout_queue; @@ -2302,7 +2302,7 @@ static int pktio_check_pktin_ts(void) static void pktio_test_pktin_ts(void) { odp_pktio_t pktio_tx, pktio_rx; - odp_pktio_t pktio[MAX_NUM_IFACES]; + odp_pktio_t pktio[MAX_NUM_IFACES] = {0}; pktio_info_t pktio_rx_info; odp_pktio_capability_t capa; odp_pktio_config_t config; @@ -2417,7 +2417,7 @@ static int pktio_check_pktout_ts(void) static void pktio_test_pktout_ts(void) { odp_packet_t pkt_tbl[TX_BATCH_LEN]; - odp_pktio_t pktio[MAX_NUM_IFACES]; + odp_pktio_t pktio[MAX_NUM_IFACES] = {0}; odp_pktout_queue_t pktout_queue; odp_pktio_t pktio_tx, pktio_rx; uint32_t pkt_seq[TX_BATCH_LEN]; @@ -3381,7 +3381,7 @@ static void pktio_test_pktv_pktin_queue_config_sched(void) static void pktio_test_recv_maxlen_set(void) { odp_pktio_t pktio_tx, pktio_rx; - odp_pktio_t pktio[MAX_NUM_IFACES]; + odp_pktio_t pktio[MAX_NUM_IFACES] = {0}; pktio_info_t pktio_rx_info; odp_pktio_capability_t capa; odp_pktio_config_t config; -- cgit v1.2.3 From 33d47b0e64ee2e94a8d12b0700f7f2fd9349fd20 Mon Sep 17 00:00:00 2001 From: Malvika Gupta Date: Tue, 9 Feb 2021 17:45:50 -0600 Subject: DEPENDENCIES: add instructions for installing RPM-based packages Instructions for installing various RPM-based packages were missing and have been added. For CentOS/Red Hat systems, some packages require the installation of Fedora EPEL package. For CentOS 8 systems, the powertools repository must be enabled to install the libconfig-devel, doxygen and CUnit-devel packages. These additional steps have also been captured in the file. Signed-off-by: Malvika Gupta Reviewed-by: Govindarajan Mohandoss Reviewed-by: Matias Elo --- DEPENDENCIES | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 30745c1ef..ba63313cb 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -5,6 +5,14 @@ Prerequisites for building the OpenDataPlane (ODP) API Linux distributions tested by the ODP CI. Earlier versions may or may not work. + For CentOS/RedHat distros, configure the system to use Fedora EPEL repos and + third-party packages: + $ sudo yum install epel-release + + Additionally, for CentOS 8 distros, enable the powertools repository: + $ sudo yum install dnf-plugins-core + $ sudo yum config-manager --set-enabled powertools + 2. autotools automake @@ -23,10 +31,10 @@ Prerequisites for building the OpenDataPlane (ODP) API Libraries currently required to link: libconfig, openssl, libatomic On Debian/Ubuntu systems: - $ sudo apt-get install libconfig-dev + $ sudo apt-get install libconfig-dev libatomic On CentOS/RedHat/Fedora systems: - $ sudo yum install libconfig-devel + $ sudo yum install libconfig-devel libatomic It is possible to build ODP without OpenSSL by passing flag --without-openssl to configure script. However this will result in @@ -183,6 +191,7 @@ Prerequisites for building the OpenDataPlane (ODP) API DPDK pktio adds a dependency to NUMA library. # Debian/Ubuntu $ sudo apt-get install libnuma-dev + # CentOS/RedHat/Fedora $ sudo yum install numactl-devel @@ -245,7 +254,10 @@ Prerequisites for building the OpenDataPlane (ODP) API 4.1 Native CUnit install # Debian/Ubuntu - $ apt-get install libcunit1-dev + $ sudo apt-get install libcunit1-dev + + # CentOS/RedHat/Fedora systems + $ sudo yum install CUnit-devel 4.2 Built from src @@ -341,7 +353,10 @@ Prerequisites for building the OpenDataPlane (ODP) API Message sequence diagrams are stored as msc files and the svg versions are generated when the docs are built. # Debian/Ubuntu - $ apt-get install mscgen + $ sudo apt-get install mscgen + + # CentOS 8/RedHat/Fedora + $ sudo yum install mscgen 6.1 API Guide See https://www.doxygen.nl/manual/install.html @@ -350,13 +365,19 @@ Prerequisites for building the OpenDataPlane (ODP) API 6.1.1 HTML # Debian/Ubuntu - $ apt-get install doxygen graphviz + $ sudo apt-get install doxygen graphviz + + # CentOS/RedHat/Fedora + $ sudo yum install doxygen graphviz 6.2 User guides 6.2.1 HTML # Debian/Ubuntu - $ apt-get install asciidoctor source-highlight librsvg2-bin + $ sudo apt-get install asciidoctor source-highlight librsvg2-bin + + # CentOS/RedHat/Fedora + $ sudo yum install asciidoc source-highlight librsvg2 7.0 Submitting patches -- cgit v1.2.3 From 2dcaaefe6c4d23676a3b474e96e274c811fc687a Mon Sep 17 00:00:00 2001 From: Janne Peltonen Date: Fri, 12 Feb 2021 17:51:58 +0200 Subject: linux-gen: ipsec: fix lookup parameters returned by SA info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current code writes the SA lookup parameters in odp_ipsec_sa_info_t only for tunnel mode SAs even though the parameters are not tunnel mode specific. Fix the problem by filling the address and address pointer fields also for transport mode SAs. Make the address pointer point to the address field regardless of lookup mode to follow the API spec more closely. In other lookup modes than DSTADDR_SPI the address field remains filled with zeroes. Signed-off-by: Janne Peltonen Reviewed-by: Jere Leppänen Reviewed-by: Aakash Sasidharan --- platform/linux-generic/odp_ipsec_sad.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/linux-generic/odp_ipsec_sad.c b/platform/linux-generic/odp_ipsec_sad.c index 0e021361c..a4a349077 100644 --- a/platform/linux-generic/odp_ipsec_sad.c +++ b/platform/linux-generic/odp_ipsec_sad.c @@ -1007,8 +1007,9 @@ static void ipsec_out_sa_info(ipsec_sa_t *ipsec_sa, odp_ipsec_sa_info_t *sa_info static void ipsec_in_sa_info(ipsec_sa_t *ipsec_sa, odp_ipsec_sa_info_t *sa_info) { - if (ipsec_sa->param.mode == ODP_IPSEC_MODE_TUNNEL) { - uint8_t *dst = sa_info->inbound.lookup_param.dst_addr; + uint8_t *dst = sa_info->inbound.lookup_param.dst_addr; + + if (ipsec_sa->lookup_mode == ODP_IPSEC_LOOKUP_DSTADDR_SPI) { if (ipsec_sa->param.inbound.lookup_param.ip_version == ODP_IPSEC_IPV4) @@ -1018,8 +1019,8 @@ static void ipsec_in_sa_info(ipsec_sa_t *ipsec_sa, odp_ipsec_sa_info_t *sa_info) memcpy(dst, &ipsec_sa->in.lookup_dst_ipv6, ODP_IPV6_ADDR_SIZE); - sa_info->param.inbound.lookup_param.dst_addr = dst; } + sa_info->param.inbound.lookup_param.dst_addr = dst; if (ipsec_sa->antireplay) { sa_info->inbound.antireplay_ws = IPSEC_ANTIREPLAY_WS; -- cgit v1.2.3 From 19a2dbaca2eb05bac456c9e771ae2da9161d5bb0 Mon Sep 17 00:00:00 2001 From: Janne Peltonen Date: Fri, 12 Feb 2021 17:52:08 +0200 Subject: validation: ipsec: improve odp_ipsec_sa_info() testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a check that lookup parameters are returned correctly for a transport mode SA that uses dst_addr+SPI based lookup. Signed-off-by: Janne Peltonen Reviewed-by: Jere Leppänen Reviewed-by: Aakash Sasidharan --- test/validation/api/ipsec/ipsec_test_out.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/validation/api/ipsec/ipsec_test_out.c b/test/validation/api/ipsec/ipsec_test_out.c index b4065d667..7035f9512 100644 --- a/test/validation/api/ipsec/ipsec_test_out.c +++ b/test/validation/api/ipsec/ipsec_test_out.c @@ -1284,6 +1284,7 @@ static void test_sa_info(void) param_in.inbound.antireplay_ws = 32; sa_in = odp_ipsec_sa_create(¶m_in); + CU_ASSERT_FATAL(sa_in != ODP_IPSEC_SA_INVALID); memset(&info_out, 0, sizeof(info_out)); CU_ASSERT_EQUAL_FATAL(0, odp_ipsec_sa_info(sa_out, &info_out)); @@ -1362,6 +1363,33 @@ static void test_sa_info(void) ipsec_sa_destroy(sa_out); ipsec_sa_destroy(sa_in); + + /* + * Additional check for SA lookup parameters. Let's use transport + * mode SA and ODP_IPSEC_DSTADD_SPI lookup mode. + */ + ipsec_sa_param_fill(¶m_in, + true, false, 123, NULL, + ODP_CIPHER_ALG_AES_CBC, &key_a5_128, + ODP_AUTH_ALG_SHA1_HMAC, &key_5a_160, + NULL, NULL); + param_in.inbound.lookup_mode = ODP_IPSEC_LOOKUP_DSTADDR_SPI; + param_in.inbound.lookup_param.ip_version = ODP_IPSEC_IPV4; + param_in.inbound.lookup_param.dst_addr = &dst; + sa_in = odp_ipsec_sa_create(¶m_in); + CU_ASSERT_FATAL(sa_in != ODP_IPSEC_SA_INVALID); + + memset(&info_in, 0, sizeof(info_in)); + CU_ASSERT_FATAL(odp_ipsec_sa_info(sa_in, &info_in) == 0); + + CU_ASSERT(info_in.param.inbound.lookup_mode == + ODP_IPSEC_LOOKUP_DSTADDR_SPI); + CU_ASSERT_FATAL(info_in.param.inbound.lookup_param.dst_addr == + &info_in.inbound.lookup_param.dst_addr); + CU_ASSERT(!memcmp(info_in.param.inbound.lookup_param.dst_addr, + &dst, + ODP_IPV4_ADDR_SIZE)); + ipsec_sa_destroy(sa_in); } static void ipsec_test_capability(void) -- cgit v1.2.3 From e1cf47812feb4db8c5f8c8e05f8d91355f29d820 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Fri, 19 Feb 2021 11:34:22 +0200 Subject: checkpatch: ignore PREFER_ARRAY_SIZE warnings Ignore warnings about preferred usage of non-standard ARRAY_SIZE() macro. Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- .checkpatch.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/.checkpatch.conf b/.checkpatch.conf index 7c179e3e8..fa31c1edf 100644 --- a/.checkpatch.conf +++ b/.checkpatch.conf @@ -11,6 +11,7 @@ --ignore=VOLATILE --ignore=AVOID_EXTERNS --ignore=CONST_STRUCT +--ignore=PREFER_ARRAY_SIZE --ignore=PREFER_KERNEL_TYPES --ignore=CONSTANT_COMPARISON --ignore=BLOCK_COMMENT_STYLE -- cgit v1.2.3 From e9aaa0c664582c137d17c764d9ef6f29c626a6fb Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 17 Feb 2021 10:47:20 +0200 Subject: test: performance: add new atomic operation benchmark application Add new performance test application for atomic operations. The test repeats each atomic operation 'num_round' times and measures the maximum rate of operations. Each worker thread can have a private atomic variable on a separate cache line ('-p 1'), or all threads can share a common variable (default). Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- test/performance/.gitignore | 1 + test/performance/Makefile.am | 4 +- test/performance/odp_atomic_perf.c | 1184 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1188 insertions(+), 1 deletion(-) create mode 100644 test/performance/odp_atomic_perf.c diff --git a/test/performance/.gitignore b/test/performance/.gitignore index 80396e5d9..0e6d9ef57 100644 --- a/test/performance/.gitignore +++ b/test/performance/.gitignore @@ -1,6 +1,7 @@ *.log *.trs odp_atomic +odp_atomic_perf odp_bench_packet odp_cpu_bench odp_crypto diff --git a/test/performance/Makefile.am b/test/performance/Makefile.am index 624795f8b..7566ab8a8 100644 --- a/test/performance/Makefile.am +++ b/test/performance/Makefile.am @@ -2,7 +2,8 @@ include $(top_srcdir)/test/Makefile.inc TESTS_ENVIRONMENT += TEST_DIR=${builddir} -EXECUTABLES = odp_bench_packet \ +EXECUTABLES = odp_atomic_perf \ + odp_bench_packet \ odp_cpu_bench \ odp_crypto \ odp_ipsec \ @@ -39,6 +40,7 @@ endif bin_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) +odp_atomic_perf_SOURCES = odp_atomic_perf.c odp_bench_packet_SOURCES = odp_bench_packet.c odp_cpu_bench_SOURCES = odp_cpu_bench.c odp_crypto_SOURCES = odp_crypto.c diff --git a/test/performance/odp_atomic_perf.c b/test/performance/odp_atomic_perf.c new file mode 100644 index 000000000..2ed88a5e8 --- /dev/null +++ b/test/performance/odp_atomic_perf.c @@ -0,0 +1,1184 @@ +/* Copyright (c) 2021, Nokia + * + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Default number of test rounds */ +#define NUM_ROUNDS 1000000u + +/* Initial value for atomic variables */ +#define INIT_VAL 1234567 + +/* Max number of workers if num_cpu=0 */ +#define DEFAULT_MAX_WORKERS 10 + +#define TEST_INFO(name, test, validate, op_type) \ + {name, test, validate, op_type} + +/* Test function template */ +typedef void (*test_fn_t)(void *val, void *out, uint32_t num_round); +/* Test result validation function template */ +typedef int (*validate_fn_t)(void *val, void *out, uint32_t num_round, + uint32_t num_worker, int private); + +typedef enum { + OP_32BIT, + OP_64BIT +} op_bit_t; + +/* Command line options */ +typedef struct test_options_t { + uint32_t num_cpu; + uint32_t num_round; + int private; + +} test_options_t; + +/* Cache aligned atomics for private mode operation */ +typedef struct ODP_ALIGNED_CACHE test_atomic_t { + union { + odp_atomic_u32_t u32; + odp_atomic_u64_t u64; + }; +} test_atomic_t; + +typedef struct test_global_t test_global_t; + +/* Worker thread context */ +typedef struct test_thread_ctx_t { + test_global_t *global; + test_fn_t func; + uint64_t nsec; + uint32_t idx; + op_bit_t type; + +} test_thread_ctx_t; + +/* Global data */ +struct test_global_t { + test_options_t test_options; + odp_barrier_t barrier; + union { + odp_atomic_u32_t atomic_u32; + odp_atomic_u64_t atomic_u64; + }; + odp_cpumask_t cpumask; + odph_thread_t thread_tbl[ODP_THREAD_COUNT_MAX]; + test_thread_ctx_t thread_ctx[ODP_THREAD_COUNT_MAX]; + test_atomic_t atomic_private[ODP_THREAD_COUNT_MAX]; + union { + uint32_t u32; + uint64_t u64; + } output[ODP_THREAD_COUNT_MAX]; +}; + +typedef struct { + const char *name; + test_fn_t test_fn; + validate_fn_t validate_fn; + op_bit_t type; +} test_case_t; + +static test_global_t *test_global; + +static inline void test_atomic_load_u32(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t *result = out; + uint32_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_load_u32(atomic_val); + + *result = ret; +} + +static inline void test_atomic_load_u64(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t *result = out; + uint64_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_load_u64(atomic_val); + + *result = ret; +} + +static inline int validate_atomic_init_val_u32(void *val, void *out, uint32_t num_round, + uint32_t num_worker ODP_UNUSED, + int private ODP_UNUSED) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t *result = out; + + return (odp_atomic_load_u32(atomic_val) != INIT_VAL) || + (*result != (uint32_t)INIT_VAL * num_round); +} + +static inline int validate_atomic_init_val_u64(void *val, void *out ODP_UNUSED, + uint32_t num_round ODP_UNUSED, + uint32_t worker ODP_UNUSED, int private ODP_UNUSED) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t *result = out; + + return (odp_atomic_load_u64(atomic_val) != INIT_VAL) || + (*result != (uint64_t)INIT_VAL * num_round); +} + +static inline void test_atomic_store_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_val = INIT_VAL + 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_store_u32(atomic_val, new_val++); +} + +static inline void test_atomic_store_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_val = INIT_VAL + 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_store_u64(atomic_val, new_val++); +} + +static inline int validate_atomic_num_round_u32(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t worker ODP_UNUSED, int private ODP_UNUSED) +{ + odp_atomic_u32_t *atomic_val = val; + + return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL + num_round); +} + +static inline int validate_atomic_num_round_u64(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t worker ODP_UNUSED, int private ODP_UNUSED) +{ + odp_atomic_u64_t *atomic_val = val; + + return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL + num_round); +} + +static inline void test_atomic_fetch_add_u32(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t *result = out; + uint32_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_add_u32(atomic_val, 1); + + *result = ret; +} + +static inline void test_atomic_fetch_add_u64(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t *result = out; + uint64_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_add_u64(atomic_val, 1); + + *result = ret; +} + +static inline int validate_atomic_add_round_u32(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker, int private) +{ + odp_atomic_u32_t *atomic_val = val; + + if (private) + return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL + num_round); + + return odp_atomic_load_u32(atomic_val) != (INIT_VAL + (num_worker * num_round)); +} + +static inline int validate_atomic_add_round_u64(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker, int private) +{ + odp_atomic_u64_t *atomic_val = val; + + if (private) + return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL + num_round); + + return odp_atomic_load_u64(atomic_val) != (INIT_VAL + ((uint64_t)num_worker * num_round)); +} + +static inline void test_atomic_add_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_add_u32(atomic_val, 1); +} + +static inline void test_atomic_add_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_add_u64(atomic_val, 1); +} + +static inline void test_atomic_fetch_sub_u32(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t *result = out; + uint32_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_sub_u32(atomic_val, 1); + + *result = ret; +} + +static inline void test_atomic_fetch_sub_u64(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t *result = out; + uint64_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_sub_u64(atomic_val, 1); + + *result = ret; +} + +static inline int validate_atomic_sub_round_u32(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker, int private) +{ + odp_atomic_u32_t *atomic_val = val; + + if (private) + return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL - num_round); + + return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL - (num_worker * num_round)); +} + +static inline int validate_atomic_sub_round_u64(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker, int private) +{ + odp_atomic_u64_t *atomic_val = val; + + if (private) + return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL - num_round); + + return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL - + ((uint64_t)num_worker * num_round)); +} + +static inline void test_atomic_sub_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_sub_u32(atomic_val, 1); +} + +static inline void test_atomic_sub_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_sub_u64(atomic_val, 1); +} + +static inline void test_atomic_fetch_inc_u32(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t *result = out; + uint32_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_inc_u32(atomic_val); + + *result = ret; +} + +static inline void test_atomic_fetch_inc_u64(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t *result = out; + uint64_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_inc_u64(atomic_val); + + *result = ret; +} + +static inline void test_atomic_inc_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_inc_u32(atomic_val); +} + +static inline void test_atomic_inc_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_inc_u64(atomic_val); +} + +static inline void test_atomic_fetch_dec_u32(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t *result = out; + uint32_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_dec_u32(atomic_val); + + *result = ret; +} + +static inline void test_atomic_fetch_dec_u64(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t *result = out; + uint64_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_fetch_dec_u64(atomic_val); + + *result = ret; +} + +static inline void test_atomic_dec_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_dec_u32(atomic_val); +} + +static inline void test_atomic_dec_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_dec_u64(atomic_val); +} + +static inline void test_atomic_max_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_max = INIT_VAL + 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_max_u32(atomic_val, new_max++); +} + +static inline void test_atomic_max_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_max = INIT_VAL + 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_max_u64(atomic_val, new_max++); +} + +static inline int validate_atomic_max_u32(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED) +{ + uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val); + + return (result != ((uint32_t)INIT_VAL + num_round)) && (result != UINT32_MAX); +} + +static inline int validate_atomic_max_u64(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED) +{ + uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val); + + return (result != ((uint64_t)INIT_VAL + num_round)) && (result != UINT64_MAX); +} + +static inline void test_atomic_min_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_min = INIT_VAL - 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_min_u32(atomic_val, new_min--); +} + +static inline void test_atomic_min_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_min = INIT_VAL - 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_min_u64(atomic_val, new_min--); +} + +static inline int validate_atomic_min_u32(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED) +{ + uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val); + + return result != ((uint32_t)INIT_VAL - num_round) && result != 0; +} + +static inline int validate_atomic_min_u64(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED) +{ + uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val); + + return result != ((uint64_t)INIT_VAL - num_round) && result != 0; +} + +static inline void test_atomic_cas_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_val = INIT_VAL + 1; + uint32_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_u32(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static inline void test_atomic_cas_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_val = INIT_VAL + 1; + uint64_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_u64(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static inline int validate_atomic_cas_u32(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker ODP_UNUSED, int private) +{ + uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val); + + if (private) + return result != ((uint32_t)INIT_VAL + num_round); + + return result > ((uint32_t)INIT_VAL + num_round); +} + +static inline int validate_atomic_cas_u64(void *val, void *out ODP_UNUSED, uint32_t num_round, + uint32_t num_worker ODP_UNUSED, int private) +{ + uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val); + + if (private) + return result != ((uint64_t)INIT_VAL + num_round); + + return result > ((uint64_t)INIT_VAL + num_round); +} + +static inline void test_atomic_xchg_u32(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_val = INIT_VAL + 1; + uint32_t *result = out; + uint32_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_xchg_u32(atomic_val, new_val++); + + *result = ret; +} + +static inline void test_atomic_xchg_u64(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_val = INIT_VAL + 1; + uint64_t *result = out; + uint64_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_xchg_u64(atomic_val, new_val++); + + *result = ret; +} + +static inline void test_atomic_load_acq_u32(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t *result = out; + uint32_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_load_acq_u32(atomic_val); + + *result = ret; +} + +static inline void test_atomic_load_acq_u64(void *val, void *out, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t *result = out; + uint64_t ret = 0; + + for (uint32_t i = 0; i < num_round; i++) + ret += odp_atomic_load_acq_u64(atomic_val); + + *result = ret; +} + +static inline void test_atomic_store_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_val = INIT_VAL + 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_store_rel_u32(atomic_val, new_val++); +} + +static inline void test_atomic_store_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_val = INIT_VAL + 1; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_store_rel_u64(atomic_val, new_val++); +} + +static inline void test_atomic_add_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_add_rel_u32(atomic_val, 1); +} + +static inline void test_atomic_add_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_add_rel_u64(atomic_val, 1); +} + +static inline void test_atomic_sub_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_sub_rel_u32(atomic_val, 1); +} + +static inline void test_atomic_sub_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + + for (uint32_t i = 0; i < num_round; i++) + odp_atomic_sub_rel_u64(atomic_val, 1); +} + +static inline void test_atomic_cas_acq_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_val = INIT_VAL + 1; + uint32_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_acq_u32(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static inline void test_atomic_cas_acq_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_val = INIT_VAL + 1; + uint64_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_acq_u64(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static inline void test_atomic_cas_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_val = INIT_VAL + 1; + uint32_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_rel_u32(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static inline void test_atomic_cas_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_val = INIT_VAL + 1; + uint64_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_rel_u64(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static inline void test_atomic_cas_acq_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u32_t *atomic_val = val; + uint32_t new_val = INIT_VAL + 1; + uint32_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_acq_rel_u32(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static inline void test_atomic_cas_acq_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round) +{ + odp_atomic_u64_t *atomic_val = val; + uint64_t new_val = INIT_VAL + 1; + uint64_t old_val = INIT_VAL; + + for (uint32_t i = 0; i < num_round; i++) { + if (odp_atomic_cas_acq_rel_u64(atomic_val, &old_val, new_val)) + old_val = new_val++; + } +} + +static void print_usage(void) +{ + printf("\n" + "Atomic operations performance test\n" + "\n" + "Usage: odp_atomic_perf [options]\n" + "\n" + " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs (or max %d) (default)\n" + " -r, --num_round Number of rounds (default %u)\n" + " -p, --private 0: The same atomic variable is shared between threads (default)\n" + " 1: Atomic variables are private to each thread\n" + " -h, --help This help\n" + "\n", DEFAULT_MAX_WORKERS, NUM_ROUNDS); +} + +static void print_info(test_options_t *test_options) +{ + odp_atomic_op_t atomic_ops; + + printf("\nAtomic operations performance test configuration:\n"); + printf(" num cpu %u\n", test_options->num_cpu); + printf(" num rounds %u\n", test_options->num_round); + printf(" private %i\n", test_options->private); + printf("\n"); + + atomic_ops.all_bits = 0; + odp_atomic_lock_free_u64(&atomic_ops); + + printf("\nAtomic operations lock-free:\n"); + printf(" odp_atomic_load_u64: %" PRIu32 "\n", atomic_ops.op.load); + printf(" odp_atomic_store_u64: %" PRIu32 "\n", atomic_ops.op.store); + printf(" odp_atomic_fetch_add_u64: %" PRIu32 "\n", atomic_ops.op.fetch_add); + printf(" odp_atomic_add_u64: %" PRIu32 "\n", atomic_ops.op.add); + printf(" odp_atomic_fetch_sub_u64: %" PRIu32 "\n", atomic_ops.op.fetch_sub); + printf(" odp_atomic_sub_u64: %" PRIu32 "\n", atomic_ops.op.sub); + printf(" odp_atomic_fetch_inc_u64: %" PRIu32 "\n", atomic_ops.op.fetch_inc); + printf(" odp_atomic_inc_u64: %" PRIu32 "\n", atomic_ops.op.inc); + printf(" odp_atomic_fetch_dec_u64: %" PRIu32 "\n", atomic_ops.op.fetch_dec); + printf(" odp_atomic_dec_u64: %" PRIu32 "\n", atomic_ops.op.dec); + printf(" odp_atomic_min_u64: %" PRIu32 "\n", atomic_ops.op.min); + printf(" odp_atomic_max_u64: %" PRIu32 "\n", atomic_ops.op.max); + printf(" odp_atomic_cas_u64: %" PRIu32 "\n", atomic_ops.op.cas); + printf(" odp_atomic_xchg_u64: %" PRIu32 "\n", atomic_ops.op.xchg); + printf("\n\n"); +} + +static int parse_options(int argc, char *argv[], test_options_t *test_options) +{ + int opt; + int long_index; + int ret = 0; + + static const struct option longopts[] = { + {"num_cpu", required_argument, NULL, 'c'}, + {"num_round", required_argument, NULL, 'r'}, + {"private", required_argument, NULL, 'p'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + static const char *shortopts = "+c:r:p:h"; + + memset(test_options, 0, sizeof(test_options_t)); + test_options->num_cpu = 0; + test_options->num_round = NUM_ROUNDS; + test_options->private = 0; + + while (1) { + opt = getopt_long(argc, argv, shortopts, longopts, &long_index); + + if (opt == -1) + break; + + switch (opt) { + case 'c': + test_options->num_cpu = atoi(optarg); + break; + case 'r': + test_options->num_round = atol(optarg); + break; + case 'p': + test_options->private = atoi(optarg); + break; + case 'h': + /* fall through */ + default: + print_usage(); + ret = -1; + break; + } + } + + if (test_options->num_round < 1) { + ODPH_ERR("Invalid number of test rounds: %" PRIu32 "\n", test_options->num_round); + return -1; + } + + return ret; +} + +static int set_num_cpu(test_global_t *global) +{ + int ret, max_num; + test_options_t *test_options = &global->test_options; + int num_cpu = test_options->num_cpu; + + /* One thread used for the main thread */ + if (num_cpu > ODP_THREAD_COUNT_MAX - 1) { + ODPH_ERR("Too many workers. Maximum is %i.\n", ODP_THREAD_COUNT_MAX - 1); + return -1; + } + + max_num = num_cpu; + if (num_cpu == 0) { + max_num = ODP_THREAD_COUNT_MAX - 1; + if (max_num > DEFAULT_MAX_WORKERS) + max_num = DEFAULT_MAX_WORKERS; + } + + ret = odp_cpumask_default_worker(&global->cpumask, max_num); + + if (num_cpu && ret != num_cpu) { + ODPH_ERR("Too many workers. Max supported %i.\n", ret); + return -1; + } + + /* Zero: all available workers */ + if (num_cpu == 0) { + if (ret > max_num) { + ODPH_ERR("Too many cpus from odp_cpumask_default_worker(): %i\n", ret); + return -1; + } + + num_cpu = ret; + test_options->num_cpu = num_cpu; + } + + odp_barrier_init(&global->barrier, num_cpu); + + return 0; +} + +static int init_test(test_global_t *global, const char *name, op_bit_t type) +{ + printf("TEST: %s\n", name); + + if (type == OP_32BIT) + odp_atomic_init_u32(&global->atomic_u32, INIT_VAL); + else if (type == OP_64BIT) + odp_atomic_init_u64(&global->atomic_u64, INIT_VAL); + else + return -1; + + for (int i = 0; i < ODP_THREAD_COUNT_MAX; i++) { + if (type == OP_32BIT) { + global->output[i].u32 = 0; + odp_atomic_init_u32(&global->atomic_private[i].u32, INIT_VAL); + } else { + global->output[i].u64 = 0; + odp_atomic_init_u64(&global->atomic_private[i].u64, INIT_VAL); + } + } + return 0; +} + +static int run_test(void *arg) +{ + uint64_t nsec; + odp_time_t t1, t2; + test_thread_ctx_t *thread_ctx = arg; + test_global_t *global = thread_ctx->global; + test_options_t *test_options = &global->test_options; + uint32_t num_round = test_options->num_round; + uint32_t idx = thread_ctx->idx; + test_fn_t test_func = thread_ctx->func; + op_bit_t type = thread_ctx->type; + void *val; + void *out; + uint32_t out_u32 = 0; + uint64_t out_u64 = 0; + + if (type == OP_32BIT) { + val = &global->atomic_u32; + out = &out_u32; + } else { + val = &global->atomic_u64; + out = &out_u64; + } + + if (global->test_options.private) { + if (type == OP_32BIT) + val = &global->atomic_private[idx].u32; + else + val = &global->atomic_private[idx].u64; + } + + /* Start all workers at the same time */ + odp_barrier_wait(&global->barrier); + + t1 = odp_time_local(); + + test_func(val, out, num_round); + + t2 = odp_time_local(); + + nsec = odp_time_diff_ns(t2, t1); + + /* Update stats */ + thread_ctx->nsec = nsec; + if (type == OP_32BIT) + global->output[idx].u32 = out_u32; + else + global->output[idx].u64 = out_u64; + + return 0; +} + +static int start_workers(test_global_t *global, odp_instance_t instance, + test_fn_t func, op_bit_t type) +{ + odph_thread_common_param_t param; + int i, ret; + test_options_t *test_options = &global->test_options; + int num_cpu = test_options->num_cpu; + odph_thread_param_t thr_param[num_cpu]; + + memset(¶m, 0, sizeof(odph_thread_common_param_t)); + param.instance = instance; + param.cpumask = &global->cpumask; + + memset(thr_param, 0, sizeof(thr_param)); + for (i = 0; i < num_cpu; i++) { + test_thread_ctx_t *thread_ctx = &global->thread_ctx[i]; + + thread_ctx->global = global; + thread_ctx->idx = i; + thread_ctx->func = func; + thread_ctx->type = type; + + thr_param[i].thr_type = ODP_THREAD_WORKER; + thr_param[i].start = run_test; + thr_param[i].arg = thread_ctx; + } + + ret = odph_thread_create(global->thread_tbl, ¶m, thr_param, num_cpu); + if (ret != num_cpu) { + ODPH_ERR("Failed to create all threads %i\n", ret); + return -1; + } + + return 0; +} + +static int validate_results(test_global_t *global, validate_fn_t validate, op_bit_t type) +{ + int i; + test_options_t *test_options = &global->test_options; + uint32_t num_round = test_options->num_round; + int num_cpu = test_options->num_cpu; + int private = global->test_options.private; + void *val; + void *out; + + for (i = 0; i < num_cpu; i++) { + if (type == OP_32BIT) { + out = &global->output[i].u32; + val = &global->atomic_u32; + if (private) + val = &global->atomic_private[i].u32; + } else { + out = &global->output[i].u64; + val = &global->atomic_u64; + if (private) + val = &global->atomic_private[i].u64; + } + + if (validate(val, out, num_round, num_cpu, private)) + return -1; + } + return 0; +} + +static void print_stat(test_global_t *global) +{ + int i, num; + double nsec_ave; + test_options_t *test_options = &global->test_options; + int num_cpu = test_options->num_cpu; + uint32_t num_round = test_options->num_round; + uint64_t nsec_sum = 0; + + for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) + nsec_sum += global->thread_ctx[i].nsec; + + if (nsec_sum == 0) { + printf("No results.\n"); + return; + } + + nsec_ave = nsec_sum / num_cpu; + num = 0; + + printf("---------------------------------------------\n"); + printf("Per thread results (Millions of ops per sec):\n"); + printf("---------------------------------------------\n"); + printf(" 1 2 3 4 5 6 7 8 9 10"); + + for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) { + if (global->thread_ctx[i].nsec) { + if ((num % 10) == 0) + printf("\n "); + + printf("%8.2f ", num_round / (global->thread_ctx[i].nsec / 1000.0)); + num++; + } + } + printf("\n\n"); + + printf("Average results over %i threads:\n", num_cpu); + printf("---------------------------------------\n"); + printf(" duration: %8.2f sec\n", nsec_ave / ODP_TIME_SEC_IN_NS); + printf(" operations per cpu: %8.2fM ops/sec\n", num_round / (nsec_ave / 1000.0)); + printf(" total operations: %8.2fM ops/sec\n", + (num_cpu * num_round) / (nsec_ave / 1000.0)); + printf("\n\n"); +} + +/** + * Test functions + */ +static test_case_t test_suite[] = { + TEST_INFO("odp_atomic_load_u32", test_atomic_load_u32, + validate_atomic_init_val_u32, OP_32BIT), + TEST_INFO("odp_atomic_store_u32", test_atomic_store_u32, + validate_atomic_num_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_fetch_add_u32", test_atomic_fetch_add_u32, + validate_atomic_add_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_add_u32", test_atomic_add_u32, + validate_atomic_add_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_fetch_sub_u32", test_atomic_fetch_sub_u32, + validate_atomic_sub_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_sub_u32", test_atomic_sub_u32, + validate_atomic_sub_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_fetch_inc_u32", test_atomic_fetch_inc_u32, + validate_atomic_add_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_inc_u32", test_atomic_inc_u32, + validate_atomic_add_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_fetch_dec_u32", test_atomic_fetch_dec_u32, + validate_atomic_sub_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_dec_u32", test_atomic_dec_u32, + validate_atomic_sub_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_max_u32", test_atomic_max_u32, + validate_atomic_max_u32, OP_32BIT), + TEST_INFO("odp_atomic_min_u32", test_atomic_min_u32, + validate_atomic_min_u32, OP_32BIT), + TEST_INFO("odp_atomic_cas_u32", test_atomic_cas_u32, + validate_atomic_cas_u32, OP_32BIT), + TEST_INFO("odp_atomic_xchg_u32", test_atomic_xchg_u32, + validate_atomic_num_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_load_acq_u32", test_atomic_load_acq_u32, + validate_atomic_init_val_u32, OP_32BIT), + TEST_INFO("odp_atomic_store_rel_u32", test_atomic_store_rel_u32, + validate_atomic_num_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_add_rel_u32", test_atomic_add_rel_u32, + validate_atomic_add_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_sub_rel_u32", test_atomic_sub_rel_u32, + validate_atomic_sub_round_u32, OP_32BIT), + TEST_INFO("odp_atomic_cas_acq_u32", test_atomic_cas_acq_u32, + validate_atomic_cas_u32, OP_32BIT), + TEST_INFO("odp_atomic_cas_rel_u32", test_atomic_cas_rel_u32, + validate_atomic_cas_u32, OP_32BIT), + TEST_INFO("odp_atomic_cas_acq_rel_u32", test_atomic_cas_acq_rel_u32, + validate_atomic_cas_u32, OP_32BIT), + TEST_INFO("odp_atomic_load_u64", test_atomic_load_u64, + validate_atomic_init_val_u64, OP_64BIT), + TEST_INFO("odp_atomic_store_u64", test_atomic_store_u64, + validate_atomic_num_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_fetch_add_u64", test_atomic_fetch_add_u64, + validate_atomic_add_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_add_u64", test_atomic_add_u64, + validate_atomic_add_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_fetch_sub_u64", test_atomic_fetch_sub_u64, + validate_atomic_sub_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_sub_u64", test_atomic_sub_u64, + validate_atomic_sub_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_fetch_inc_u64", test_atomic_fetch_inc_u64, + validate_atomic_add_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_inc_u64", test_atomic_inc_u64, + validate_atomic_add_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_fetch_dec_u64", test_atomic_fetch_dec_u64, + validate_atomic_sub_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_dec_u64", test_atomic_dec_u64, + validate_atomic_sub_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_max_u64", test_atomic_max_u64, + validate_atomic_max_u64, OP_64BIT), + TEST_INFO("odp_atomic_min_u64", test_atomic_min_u64, + validate_atomic_min_u64, OP_64BIT), + TEST_INFO("odp_atomic_cas_u64", test_atomic_cas_u64, + validate_atomic_cas_u64, OP_64BIT), + TEST_INFO("odp_atomic_xchg_u64", test_atomic_xchg_u64, + validate_atomic_num_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_load_acq_u64", test_atomic_load_acq_u64, + validate_atomic_init_val_u64, OP_64BIT), + TEST_INFO("odp_atomic_store_rel_u64", test_atomic_store_rel_u64, + validate_atomic_num_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_add_rel_u64", test_atomic_add_rel_u64, + validate_atomic_add_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_sub_rel_u64", test_atomic_sub_rel_u64, + validate_atomic_sub_round_u64, OP_64BIT), + TEST_INFO("odp_atomic_cas_acq_u64", test_atomic_cas_acq_u64, + validate_atomic_cas_u64, OP_64BIT), + TEST_INFO("odp_atomic_cas_rel_u64", test_atomic_cas_rel_u64, + validate_atomic_cas_u64, OP_64BIT), + TEST_INFO("odp_atomic_cas_acq_rel_u64", test_atomic_cas_acq_rel_u64, + validate_atomic_cas_u64, OP_64BIT) +}; + +int main(int argc, char **argv) +{ + odp_instance_t instance; + odp_init_t init; + odp_shm_t shm; + test_options_t test_options; + int num_tests, i; + + if (parse_options(argc, argv, &test_options)) + exit(EXIT_FAILURE); + + /* List features not to be used */ + odp_init_param_init(&init); + init.not_used.feat.cls = 1; + init.not_used.feat.compress = 1; + init.not_used.feat.crypto = 1; + init.not_used.feat.ipsec = 1; + init.not_used.feat.schedule = 1; + init.not_used.feat.stash = 1; + init.not_used.feat.timer = 1; + init.not_used.feat.tm = 1; + + /* Init ODP before calling anything else */ + if (odp_init_global(&instance, &init, NULL)) { + ODPH_ERR("Global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Init this thread */ + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + ODPH_ERR("Local init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Reserve memory for global data from shared mem */ + shm = odp_shm_reserve("test_global", sizeof(test_global_t), + ODP_CACHE_LINE_SIZE, 0); + + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Shared memory reserve failed.\n"); + exit(EXIT_FAILURE); + } + + test_global = odp_shm_addr(shm); + if (test_global == NULL) { + ODPH_ERR("Shared memory alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(test_global, 0, sizeof(test_global_t)); + test_global->test_options = test_options; + + odp_sys_info_print(); + + if (set_num_cpu(test_global)) + exit(EXIT_FAILURE); + + print_info(&test_global->test_options); + + /* Loop all test cases */ + num_tests = sizeof(test_suite) / sizeof(test_suite[0]); + + for (i = 0; i < num_tests; i++) { + /* Initialize test variables */ + if (init_test(test_global, test_suite[i].name, test_suite[i].type)) { + ODPH_ERR("Failed to initialize atomics.\n"); + exit(EXIT_FAILURE); + } + + /* Start workers */ + if (start_workers(test_global, instance, test_suite[i].test_fn, test_suite[i].type)) + exit(EXIT_FAILURE); + + /* Wait workers to exit */ + odph_thread_join(test_global->thread_tbl, test_global->test_options.num_cpu); + + print_stat(test_global); + + /* Validate test results */ + if (validate_results(test_global, test_suite[i].validate_fn, test_suite[i].type)) { + ODPH_ERR("Test %s result validation failed.\n", test_suite[i].name); + exit(EXIT_FAILURE); + } + } + + if (odp_shm_free(shm)) { + ODPH_ERR("Shm free failed.\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_local()) { + ODPH_ERR("Local terminate failed.\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_global(instance)) { + ODPH_ERR("Global terminate failed.\n"); + exit(EXIT_FAILURE); + } + + return 0; +} -- cgit v1.2.3 From ee9a6a9a9e46aac337b8b105ef5d2c7e754ce3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Tue, 9 Feb 2021 18:12:35 +0200 Subject: helper: create autoheader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create autoheader_external for helper and move there the ODPH_* defines from odp autoheader_external. Signed-off-by: Jere Leppänen Reviewed-by: Matias Elo --- .gitignore | 2 ++ configure.ac | 21 +----------------- helper/Makefile.am | 1 + helper/include/odp/helper/autoheader_external.h.in | 11 ++++++++++ helper/include/odp/helper/odph_debug.h | 2 +- helper/m4/configure.m4 | 25 ++++++++++++++++++++++ helper/test/debug.c | 2 +- include/odp/autoheader_external.h.in | 6 ------ 8 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 helper/include/odp/helper/autoheader_external.h.in diff --git a/.gitignore b/.gitignore index 772c551f4..0a58c0ee9 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,8 @@ include/odp/autoheader_build.h include/odp/autoheader_external.h include/odp/autoheader_internal.h include/odp/stamp-h* +helper/include/odp/helper/autoheader_external.h +helper/include/odp/helper/stamp-h* lib/ libtool ltmain.sh diff --git a/configure.ac b/configure.ac index 20d5af648..2761190a3 100644 --- a/configure.ac +++ b/configure.ac @@ -43,7 +43,7 @@ AS_IF([test "$ac_cv_env_CFLAGS_set" = ""], [user_cflags=0], [user_cflags=1]) # Initialize automake AM_INIT_AUTOMAKE([1.9 tar-pax subdir-objects foreign nostdinc -Wall -Werror]) AC_CONFIG_SRCDIR([include/odp/api/spec/init.h]) -AM_CONFIG_HEADER([include/odp/autoheader_build.h include/odp/autoheader_external.h include/odp/autoheader_internal.h]) +AM_CONFIG_HEADER([include/odp/autoheader_build.h include/odp/autoheader_external.h include/odp/autoheader_internal.h helper/include/odp/helper/autoheader_external.h]) AC_USE_SYSTEM_EXTENSIONS AC_SYS_LARGEFILE @@ -356,15 +356,6 @@ AS_IF([test "x$enable_debug" != "xno"], [ODP_DEBUG=1], AC_DEFINE_UNQUOTED([ODP_DEBUG], [$ODP_DEBUG], [Define to 1 to include additional debug code]) -AC_ARG_ENABLE([helper-debug], - [AS_HELP_STRING([--enable-helper-debug], - [helpers include additional debugging code [default=disabled]])], - [], [AS_IF([test "x$enable_debug" = "xfull"], [enable_helper_debug=yes], - [enable_helper_debug=no])]) -AS_IF([test "x$enable_helper_debug" != "xno"], [ODPH_DEBUG=1], [ODPH_DEBUG=0]) -AC_DEFINE_UNQUOTED([ODPH_DEBUG], [$ODPH_DEBUG], - [Define to 1 to include additional helper debug code]) - ########################################################################## # Enable/disable ODP_DEBUG_PRINT ########################################################################## @@ -378,16 +369,6 @@ AS_IF([test "x$enable_debug_print" != "xno"], [ODP_DEBUG_PRINT=1], AC_DEFINE_UNQUOTED([ODP_DEBUG_PRINT], [$ODP_DEBUG_PRINT], [Define to 1 to display debug information]) -AC_ARG_ENABLE([helper-debug-print], - [AS_HELP_STRING([--enable-helper-debug-print], - [display helper debugging information [default=disabled]])], - [], [AS_IF([test "x$enable_debug" = "xfull"], [enable_helper_debug_print=yes], - [enable_helper_debug_print=no])]) -AS_IF([test "x$enable_helper_debug_print" != "xno"], [ODPH_DEBUG_PRINT=1], - [ODPH_DEBUG_PRINT=0]) -AC_DEFINE_UNQUOTED([ODPH_DEBUG_PRINT], [$ODPH_DEBUG_PRINT], - [Define to 1 to display helper debug information]) - debug_settings="ODP_DEBUG=${ODP_DEBUG}, ODP_DEBUG_PRINT=${ODP_DEBUG_PRINT}, \ ODPH_DEBUG=${ODPH_DEBUG}, ODPH_DEBUG_PRINT=${ODPH_DEBUG_PRINT}" diff --git a/helper/Makefile.am b/helper/Makefile.am index 8c1c0ffc5..fc5090852 100644 --- a/helper/Makefile.am +++ b/helper/Makefile.am @@ -12,6 +12,7 @@ AM_LDFLAGS = -version-number '$(ODPHELPER_LIBSO_VERSION)' helperincludedir = $(includedir)/odp/helper/ helperinclude_HEADERS = \ + include/odp/helper/autoheader_external.h\ include/odp/helper/chksum.h\ include/odp/helper/odph_debug.h \ include/odp/helper/eth.h\ diff --git a/helper/include/odp/helper/autoheader_external.h.in b/helper/include/odp/helper/autoheader_external.h.in new file mode 100644 index 000000000..987b1027e --- /dev/null +++ b/helper/include/odp/helper/autoheader_external.h.in @@ -0,0 +1,11 @@ + +#ifndef ODPH_AUTOHEADER_EXTERNAL_H_ +#define ODPH_AUTOHEADER_EXTERNAL_H_ + +/* Define to 1 to include additional helper debug code */ +#undef ODPH_DEBUG + +/* Define to 1 to display helper debug information */ +#undef ODPH_DEBUG_PRINT + +#endif diff --git a/helper/include/odp/helper/odph_debug.h b/helper/include/odp/helper/odph_debug.h index 2fa89d8ab..39ce3f0d9 100644 --- a/helper/include/odp/helper/odph_debug.h +++ b/helper/include/odp/helper/odph_debug.h @@ -15,7 +15,7 @@ #ifndef ODPH_DEBUG_H_ #define ODPH_DEBUG_H_ -#include +#include #include #include diff --git a/helper/m4/configure.m4 b/helper/m4/configure.m4 index c25f8fe68..426dcd8ff 100644 --- a/helper/m4/configure.m4 +++ b/helper/m4/configure.m4 @@ -17,5 +17,30 @@ AC_ARG_ENABLE([helper-linux], [helper_linux=$enableval], [helper_linux=yes]) +########################################################################## +# Enable/disable ODPH_DEBUG +########################################################################## +AC_ARG_ENABLE([helper-debug], + [AS_HELP_STRING([--enable-helper-debug], + [helpers include additional debugging code [default=disabled]])], + [], [AS_IF([test "x$enable_debug" = "xfull"], [enable_helper_debug=yes], + [enable_helper_debug=no])]) +AS_IF([test "x$enable_helper_debug" != "xno"], [ODPH_DEBUG=1], [ODPH_DEBUG=0]) +AC_DEFINE_UNQUOTED([ODPH_DEBUG], [$ODPH_DEBUG], + [Define to 1 to include additional helper debug code]) + +########################################################################## +# Enable/disable ODPH_DEBUG_PRINT +########################################################################## +AC_ARG_ENABLE([helper-debug-print], + [AS_HELP_STRING([--enable-helper-debug-print], + [display helper debugging information [default=disabled]])], + [], [AS_IF([test "x$enable_debug" = "xfull"], [enable_helper_debug_print=yes], + [enable_helper_debug_print=no])]) +AS_IF([test "x$enable_helper_debug_print" != "xno"], [ODPH_DEBUG_PRINT=1], + [ODPH_DEBUG_PRINT=0]) +AC_DEFINE_UNQUOTED([ODPH_DEBUG_PRINT], [$ODPH_DEBUG_PRINT], + [Define to 1 to display helper debug information]) + AC_CONFIG_FILES([helper/libodphelper.pc helper/test/Makefile]) diff --git a/helper/test/debug.c b/helper/test/debug.c index 2431b0ecd..3b8a69d8b 100644 --- a/helper/test/debug.c +++ b/helper/test/debug.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include #include #include diff --git a/include/odp/autoheader_external.h.in b/include/odp/autoheader_external.h.in index 15626898d..978bc1f2b 100644 --- a/include/odp/autoheader_external.h.in +++ b/include/odp/autoheader_external.h.in @@ -8,10 +8,4 @@ /* Define to 1 to display debug information */ #undef ODP_DEBUG_PRINT -/* Define to 1 to include additional helper debug code */ -#undef ODPH_DEBUG - -/* Define to 1 to display helper debug information */ -#undef ODPH_DEBUG_PRINT - #endif -- cgit v1.2.3 From 84b6587531ea50a9de473587af52cdf39f7e9dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Fri, 15 Jan 2021 16:26:33 +0200 Subject: helper: add CLI helper API and implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLI helper API allows starting and stopping ODP CLI server, which may be connected to using a telnet client. CLI commands may be used to get information from an ODP instance, for debugging purposes. This implementation depends on libcli. If libcli is not available, CLI helper is automatically excluded. Signed-off-by: Jere Leppänen Reviewed-by: Matias Elo --- configure.ac | 2 + helper/Makefile.am | 11 + helper/cli.c | 499 +++++++++++++++++++++ helper/include/odp/helper/autoheader_external.h.in | 3 + helper/include/odp/helper/cli.h | 92 ++++ helper/include/odp/helper/odph_api.h | 6 + helper/libodphelper.pc.in | 2 +- helper/m4/configure.m4 | 15 + platform/linux-generic/m4/configure.m4 | 2 +- 9 files changed, 630 insertions(+), 2 deletions(-) create mode 100644 helper/cli.c create mode 100644 helper/include/odp/helper/cli.h diff --git a/configure.ac b/configure.ac index 2761190a3..83b25b4eb 100644 --- a/configure.ac +++ b/configure.ac @@ -332,6 +332,7 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test "x${DOXYGEN}" = "xdoxygen"]) AM_CONDITIONAL([user_guide], [test "x${user_guides}" = "xyes" ]) AM_CONDITIONAL([HAVE_MSCGEN], [test "x${MSCGEN}" = "xmscgen"]) AM_CONDITIONAL([helper_linux], [test x$helper_linux = xyes ]) +AM_CONDITIONAL([helper_cli], [test x$helper_cli = xyes ]) AM_CONDITIONAL([ARCH_IS_ARM], [test "x${ARCH_DIR}" = "xarm"]) AM_CONDITIONAL([ARCH_IS_AARCH64], [test "x${ARCH_DIR}" = "xaarch64"]) AM_CONDITIONAL([ARCH_IS_DEFAULT], [test "x${ARCH_DIR}" = "xdefault"]) @@ -479,6 +480,7 @@ AC_MSG_RESULT([ ARCH_ABI ${ARCH_ABI} with_platform: ${with_platform} helper_linux: ${helper_linux} + helper_cli: ${helper_cli} prefix: ${prefix} sysconfdir: ${sysconfdir} libdir: ${libdir} diff --git a/helper/Makefile.am b/helper/Makefile.am index fc5090852..9aef4f4ec 100644 --- a/helper/Makefile.am +++ b/helper/Makefile.am @@ -44,6 +44,11 @@ helperlinuxinclude_HEADERS = \ include/odp/helper/linux/process.h endif +if helper_cli +helperinclude_HEADERS += \ + include/odp/helper/cli.h +endif + noinst_HEADERS = \ include/odph_list_internal.h @@ -64,6 +69,12 @@ __LIB__libodphelper_la_SOURCES += \ linux/thread.c endif +if helper_cli +__LIB__libodphelper_la_SOURCES += \ + cli.c +endif + __LIB__libodphelper_la_LIBADD = $(PTHREAD_LIBS) +__LIB__libodphelper_la_LIBADD += $(LIBCLI_LIBS) lib_LTLIBRARIES = $(LIB)/libodphelper.la diff --git a/helper/cli.c b/helper/cli.c new file mode 100644 index 000000000..3aee88aaa --- /dev/null +++ b/helper/cli.c @@ -0,0 +1,499 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Socketpair socket roles. */ +enum { + SP_READ = 0, + SP_WRITE = 1, +}; + +typedef struct { + volatile int cli_fd; + /* Server thread will exit if this is false. */ + volatile int run; + /* Socketpair descriptors. */ + int sp[2]; + int listen_fd; + /* This lock guards cli_fd and run, which must be accessed atomically. */ + odp_spinlock_t lock; + odph_thread_t thr_server; +} cli_shm_t; + +static const char *shm_name = "_odp_cli"; + +static const odph_cli_param_t param_default = { + .address = "127.0.0.1", + .port = 55555, +}; + +void odph_cli_param_init(odph_cli_param_t *param) +{ + *param = param_default; +} + +static int cmd_show_cpu(struct cli_def *cli, const char *command ODP_UNUSED, + char *argv[] ODP_UNUSED, int argc ODP_UNUSED) +{ + for (int c = 0; c < odp_cpu_count(); c++) { + cli_print(cli, "% 4d: %s %.03f / %.03f GHz", c, + odp_cpu_model_str_id(c), + (float)odp_cpu_hz_id(c) / 1000000000.0, + (float)odp_cpu_hz_max_id(c) / 1000000000.0); + } + + return CLI_OK; +} + +static int cmd_show_version(struct cli_def *cli, const char *command ODP_UNUSED, + char *argv[] ODP_UNUSED, int argc ODP_UNUSED) +{ + cli_print(cli, "ODP API version: %s", odp_version_api_str()); + cli_print(cli, "ODP implementation name: %s", odp_version_impl_name()); + cli_print(cli, "ODP implementation version: %s", + odp_version_impl_str()); + + return CLI_OK; +} + +/* + * Check that number of given arguments matches required number of + * arguments. Print error messages if this is not the case. Return 0 + * on success, -1 otherwise. + */ +static int check_num_args(struct cli_def *cli, int argc, int req_argc) +{ + if (argc < req_argc) { + cli_error(cli, "%% Incomplete command."); + return -1; + } + + if (argc > req_argc) { + cli_error(cli, "%% Extra parameter given to command."); + return -1; + } + + return 0; +} + +static int cmd_call_odp_ipsec_print(struct cli_def *cli, + const char *command ODP_UNUSED, + char *argv[] ODP_UNUSED, int argc) +{ + if (check_num_args(cli, argc, 0)) + return CLI_ERROR; + + odp_ipsec_print(); + + return CLI_OK; +} + +static int cmd_call_odp_shm_print_all(struct cli_def *cli, + const char *command ODP_UNUSED, + char *argv[] ODP_UNUSED, int argc) +{ + if (check_num_args(cli, argc, 0)) + return CLI_ERROR; + + odp_shm_print_all(); + + return CLI_OK; +} + +static int cmd_call_odp_sys_config_print(struct cli_def *cli, + const char *command ODP_UNUSED, + char *argv[] ODP_UNUSED, int argc) +{ + if (check_num_args(cli, argc, 0)) + return CLI_ERROR; + + odp_sys_config_print(); + + return CLI_OK; +} + +static int cmd_call_odp_sys_info_print(struct cli_def *cli, + const char *command ODP_UNUSED, + char *argv[] ODP_UNUSED, int argc) +{ + if (check_num_args(cli, argc, 0)) + return CLI_ERROR; + + odp_sys_info_print(); + + return CLI_OK; +} + +static int cmd_call_odp_pktio_print(struct cli_def *cli, + const char *command ODP_UNUSED, + char *argv[], int argc) +{ + if (check_num_args(cli, argc, 1)) + return CLI_ERROR; + + odp_pktio_t hdl = odp_pktio_lookup(argv[0]); + + if (hdl == ODP_PKTIO_INVALID) { + cli_error(cli, "%% Name not found."); + return CLI_ERROR; + } + + odp_pktio_print(hdl); + + return CLI_OK; +} + +static int cmd_call_odp_pool_print(struct cli_def *cli, + const char *command ODP_UNUSED, char *argv[], + int argc) +{ + if (check_num_args(cli, argc, 1)) + return CLI_ERROR; + + odp_pool_t hdl = odp_pool_lookup(argv[0]); + + if (hdl == ODP_POOL_INVALID) { + cli_error(cli, "%% Name not found."); + return CLI_ERROR; + } + + odp_pool_print(hdl); + + return CLI_OK; +} + +static int cmd_call_odp_queue_print(struct cli_def *cli, + const char *command ODP_UNUSED, + char *argv[], int argc) +{ + if (check_num_args(cli, argc, 1)) + return CLI_ERROR; + + odp_queue_t hdl = odp_queue_lookup(argv[0]); + + if (hdl == ODP_QUEUE_INVALID) { + cli_error(cli, "%% Name not found."); + return CLI_ERROR; + } + + odp_queue_print(hdl); + + return CLI_OK; +} + +static int cmd_call_odp_shm_print(struct cli_def *cli, + const char *command ODP_UNUSED, char *argv[], + int argc) +{ + if (check_num_args(cli, argc, 1)) + return CLI_ERROR; + + odp_shm_t hdl = odp_shm_lookup(argv[0]); + + if (hdl == ODP_SHM_INVALID) { + cli_error(cli, "%% Name not found."); + return CLI_ERROR; + } + + odp_shm_print(hdl); + + return CLI_OK; +} + +static struct cli_def *create_cli(void) +{ + struct cli_command *c; + struct cli_def *cli; + + cli = cli_init(); + cli_set_banner(cli, NULL); + cli_set_hostname(cli, "ODP"); + + c = cli_register_command(cli, NULL, "show", NULL, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, + "Show information."); + cli_register_command(cli, c, "cpu", cmd_show_cpu, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, + "Show CPU information."); + cli_register_command(cli, c, "version", cmd_show_version, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, + "Show version information."); + + c = cli_register_command(cli, NULL, "call", NULL, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, + "Call ODP API function."); + cli_register_command(cli, c, "odp_ipsec_print", + cmd_call_odp_ipsec_print, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL); + cli_register_command(cli, c, "odp_pktio_print", + cmd_call_odp_pktio_print, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, ""); + cli_register_command(cli, c, "odp_pool_print", + cmd_call_odp_pool_print, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, ""); + cli_register_command(cli, c, "odp_queue_print", + cmd_call_odp_queue_print, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, ""); + cli_register_command(cli, c, "odp_shm_print_all", + cmd_call_odp_shm_print_all, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL); + cli_register_command(cli, c, "odp_shm_print", + cmd_call_odp_shm_print, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, ""); + cli_register_command(cli, c, "odp_sys_config_print", + cmd_call_odp_sys_config_print, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL); + cli_register_command(cli, c, "odp_sys_info_print", + cmd_call_odp_sys_info_print, + PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL); + + return cli; +} + +static int cli_server(void *arg ODP_UNUSED) +{ + cli_shm_t *shm = NULL; + odp_shm_t shm_hdl = odp_shm_lookup(shm_name); + + if (shm_hdl != ODP_SHM_INVALID) + shm = (cli_shm_t *)odp_shm_addr(shm_hdl); + + if (!shm) { + ODPH_ERR("Error: can't start cli server (shm %s not found)\n", shm_name); + return -1; + } + + struct cli_def *cli = create_cli(); + + while (1) { + struct pollfd pfd[2] = { + { .fd = shm->sp[SP_READ], .events = POLLIN, }, + { .fd = shm->listen_fd, .events = POLLIN, }, + }; + + if (poll(pfd, 2, -1) < 0) { + ODPH_ERR("Error: poll(): %s\n", strerror(errno)); + break; + } + + /* + * If we have an event on a socketpair socket, it's + * time to exit. + */ + if (pfd[0].revents) + break; + + /* + * If we don't have an event on the listening socket, poll + * again. + */ + if (!pfd[1].revents) + continue; + + int fd = accept(shm->listen_fd, NULL, 0); + + if (fd < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + + ODPH_ERR("Error: accept(): %s\n", strerror(errno)); + break; + } + + odp_spinlock_lock(&shm->lock); + if (!shm->run) { + /* + * odph_cli_stop() has been called. Close the + * socket we just accepted and exit. + */ + close(fd); + odp_spinlock_unlock(&shm->lock); + break; + } + shm->cli_fd = fd; + odp_spinlock_unlock(&shm->lock); + /* + * cli_loop() returns only when client is disconnected. One + * possible reason for disconnect is odph_cli_stop(). + */ + cli_loop(cli, shm->cli_fd); + close(shm->cli_fd); + } + + cli_done(cli); + + return 0; +} + +int odph_cli_start(const odp_instance_t instance, + const odph_cli_param_t *param_in) +{ + if (odp_shm_lookup(shm_name) != ODP_SHM_INVALID) { + ODPH_ERR("Error: cli server already running (shm %s exists)\n", shm_name); + return -1; + } + + cli_shm_t *shm = NULL; + odp_shm_t shm_hdl = odp_shm_reserve(shm_name, sizeof(cli_shm_t), 64, + ODP_SHM_SW_ONLY); + + if (shm_hdl != ODP_SHM_INVALID) + shm = (cli_shm_t *)odp_shm_addr(shm_hdl); + + if (!shm) { + ODPH_ERR("Error: failed to reserve shm %s\n", shm_name); + return -1; + } + + memset(shm, 0, sizeof(cli_shm_t)); + odp_spinlock_init(&shm->lock); + shm->sp[SP_READ] = shm->sp[SP_WRITE] = -1; + shm->listen_fd = -1; + shm->cli_fd = -1; + shm->run = 1; + + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, shm->sp)) { + ODPH_ERR("Error: socketpair(): %s\n", strerror(errno)); + goto error; + } + + /* Create listening socket. */ + + shm->listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (shm->listen_fd < 0) { + ODPH_ERR("Error: socket(): %s\n", strerror(errno)); + goto error; + } + + int on = 1; + + if (setsockopt(shm->listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) { + ODPH_ERR("Error: setsockopt(): %s\n", strerror(errno)); + goto error; + } + + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(param_in->port); + + switch (inet_pton(AF_INET, param_in->address, &addr.sin_addr)) { + case -1: + ODPH_ERR("Error: inet_pton(): %s\n", strerror(errno)); + goto error; + case 0: + ODPH_ERR("Error: inet_pton(): illegal address format\n"); + goto error; + } + + if (bind(shm->listen_fd, (struct sockaddr *)&addr, sizeof(addr))) { + ODPH_ERR("Error: bind(): %s\n", strerror(errno)); + goto error; + } + + if (listen(shm->listen_fd, 1)) { + ODPH_ERR("Error: listen(): %s\n", strerror(errno)); + goto error; + } + + /* Create server thread. */ + + odp_cpumask_t cpumask; + odph_thread_common_param_t thr_common; + odph_thread_param_t thr_param; + + if (odp_cpumask_default_control(&cpumask, 1) != 1) { + ODPH_ERR("Error: odp_cpumask_default_control() failed\n"); + goto error; + } + + memset(&thr_common, 0, sizeof(thr_common)); + thr_common.instance = instance; + thr_common.cpumask = &cpumask; + + memset(&thr_param, 0, sizeof(thr_param)); + thr_param.thr_type = ODP_THREAD_CONTROL; + thr_param.start = cli_server; + + memset(&shm->thr_server, 0, sizeof(shm->thr_server)); + + if (odph_thread_create(&shm->thr_server, &thr_common, &thr_param, 1) != 1) { + ODPH_ERR("Error: odph_thread_create() failed\n"); + goto error; + } + + return 0; + +error: + close(shm->sp[SP_READ]); + close(shm->sp[SP_WRITE]); + close(shm->listen_fd); + close(shm->cli_fd); + shm->run = 0; + return -1; +} + +int odph_cli_stop(void) +{ + cli_shm_t *shm = NULL; + odp_shm_t shm_hdl = odp_shm_lookup(shm_name); + + if (shm_hdl != ODP_SHM_INVALID) + shm = (cli_shm_t *)odp_shm_addr(shm_hdl); + + if (!shm) { + ODPH_ERR("Error: cli server not running (shm %s not found)\n", shm_name); + return -1; + } + + odp_spinlock_lock(&shm->lock); + shm->run = 0; + /* + * Close the current cli connection. This stops cli_loop(). + */ + close(shm->cli_fd); + odp_spinlock_unlock(&shm->lock); + + /* + * Send a message to the server thread in order to break it out of a + * blocking poll() call. + */ + int stop = 1; + int sent = send(shm->sp[SP_WRITE], &stop, + sizeof(stop), MSG_DONTWAIT | MSG_NOSIGNAL); + + if (sent != sizeof(stop)) { + ODPH_ERR("Error: send() = %d: %s\n", sent, strerror(errno)); + return -1; + } + + if (odph_thread_join(&shm->thr_server, 1) != 1) { + ODPH_ERR("Error: odph_thread_join() failed\n"); + return -1; + } + + close(shm->sp[SP_READ]); + close(shm->sp[SP_WRITE]); + close(shm->listen_fd); + + if (odp_shm_free(shm_hdl)) { + ODPH_ERR("Error: odp_shm_free() failed\n"); + return -1; + } + + return 0; +} diff --git a/helper/include/odp/helper/autoheader_external.h.in b/helper/include/odp/helper/autoheader_external.h.in index 987b1027e..6f5187a5b 100644 --- a/helper/include/odp/helper/autoheader_external.h.in +++ b/helper/include/odp/helper/autoheader_external.h.in @@ -2,6 +2,9 @@ #ifndef ODPH_AUTOHEADER_EXTERNAL_H_ #define ODPH_AUTOHEADER_EXTERNAL_H_ +/* Define to 1 to enable CLI helper */ +#undef ODPH_CLI + /* Define to 1 to include additional helper debug code */ #undef ODPH_DEBUG diff --git a/helper/include/odp/helper/cli.h b/helper/include/odp/helper/cli.h new file mode 100644 index 000000000..41e438857 --- /dev/null +++ b/helper/include/odp/helper/cli.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP CLI helper API + * + * This API allows control of ODP CLI server, which may be connected to + * using a telnet client. CLI commands may be used to get information + * from an ODP instance, for debugging purposes. + * + * Many CLI commands output the information to the console, or wherever + * ODP logs have been directed to in global init. + */ + +#ifndef ODPH_CLI_H_ +#define ODPH_CLI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * @addtogroup odph_cli ODPH CLI + * @{ + */ + +/** ODP CLI server parameters */ +typedef struct { + /** + * A character string containing an IP address. Default is + * "127.0.0.1". + */ + const char *address; + /** TCP port. Default is 55555. */ + uint16_t port; +} odph_cli_param_t; + +/** + * Initialize CLI server params + * + * Initialize an odph_cli_param_t to its default values for all + * fields. + * + * @param[out] param Pointer to parameter structure + */ +void odph_cli_param_init(odph_cli_param_t *param); + +/** + * Start CLI server + * + * Upon successful return from this function, the CLI server will be + * accepting client connections. This function spawns a new thread of + * type ODP_THREAD_CONTROL using odp_cpumask_default_control(). + * + * @param instance ODP instance + * @param param CLI server parameters to use + * @retval 0 Success + * @retval <0 Failure + */ +int odph_cli_start(const odp_instance_t instance, + const odph_cli_param_t *param); + +/** + * Stop CLI server + * + * Stop accepting new client connections and disconnect currently + * connected client. This function terminates the control thread + * created in odph_cli_start(). + * + * @retval 0 Success + * @retval <0 Failure + */ +int odph_cli_stop(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/helper/include/odp/helper/odph_api.h b/helper/include/odp/helper/odph_api.h index f3bcde208..7ab875c6e 100644 --- a/helper/include/odp/helper/odph_api.h +++ b/helper/include/odp/helper/odph_api.h @@ -38,6 +38,12 @@ extern "C" { #include #include +#include + +#ifdef ODPH_CLI +#include +#endif + #ifdef __cplusplus } #endif diff --git a/helper/libodphelper.pc.in b/helper/libodphelper.pc.in index b14335e5c..be99eeefc 100644 --- a/helper/libodphelper.pc.in +++ b/helper/libodphelper.pc.in @@ -7,5 +7,5 @@ Name: libodphelper Description: Helper for the ODP packet processing engine Version: @PKGCONFIG_VERSION@ Libs: -L${libdir} -lodphelper -Libs.private: +Libs.private: @LIBCLI_LIBS@ Cflags: -I${includedir} diff --git a/helper/m4/configure.m4 b/helper/m4/configure.m4 index 426dcd8ff..e67ca019e 100644 --- a/helper/m4/configure.m4 +++ b/helper/m4/configure.m4 @@ -42,5 +42,20 @@ AS_IF([test "x$enable_helper_debug_print" != "xno"], [ODPH_DEBUG_PRINT=1], AC_DEFINE_UNQUOTED([ODPH_DEBUG_PRINT], [$ODPH_DEBUG_PRINT], [Define to 1 to display helper debug information]) +######################################################################### +# If libcli is available, enable CLI helper +######################################################################### +helper_cli=no +AC_CHECK_HEADER(libcli.h, + [AC_CHECK_LIB(cli, cli_init, [helper_cli=yes], [], [-lcrypt])], + []) + +LIBCLI_LIBS="" +AS_IF([test "x$helper_cli" != "xno"], + [AC_DEFINE_UNQUOTED([ODPH_CLI], [1], [Define to 1 to enable CLI helper]) + LIBCLI_LIBS="-lcli -lcrypt"]) + +AC_SUBST([LIBCLI_LIBS]) + AC_CONFIG_FILES([helper/libodphelper.pc helper/test/Makefile]) diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index 4b30f09e3..22502deaf 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -27,7 +27,7 @@ m4_include([platform/linux-generic/m4/odp_netmap.m4]) m4_include([platform/linux-generic/m4/odp_dpdk.m4]) ODP_SCHEDULER -AS_VAR_APPEND([PLAT_DEP_LIBS], ["${LIBCONFIG_LIBS} ${OPENSSL_LIBS} ${DPDK_LIBS_LT}"]) +AS_VAR_APPEND([PLAT_DEP_LIBS], ["${LIBCONFIG_LIBS} ${OPENSSL_LIBS} ${DPDK_LIBS_LT} ${LIBCLI_LIBS}"]) # Add text to the end of configure with platform specific settings. # Make sure it's aligned same as other lines in configure.ac. -- cgit v1.2.3 From b1b10b702674378905a9cca643f7d404a3ca15db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Thu, 18 Feb 2021 15:07:24 +0200 Subject: configure: add with-libcli-path option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow user to specify the location of libcli headers and libraries, in case libcli is installed outside the normal search paths. Also, move all the libcli related logic to a separate libcli.m4 file. Signed-off-by: Jere Leppänen Reviewed-by: Matias Elo --- helper/Makefile.am | 3 ++- helper/m4/configure.m4 | 20 +++++--------------- helper/m4/libcli.m4 | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 helper/m4/libcli.m4 diff --git a/helper/Makefile.am b/helper/Makefile.am index 9aef4f4ec..95167c3be 100644 --- a/helper/Makefile.am +++ b/helper/Makefile.am @@ -5,7 +5,8 @@ pkgconfig_DATA = libodphelper.pc AM_CPPFLAGS = \ $(ODP_INCLUDES) \ - $(HELPER_INCLUDES) + $(HELPER_INCLUDES) \ + $(LIBCLI_CPPFLAGS) AM_CFLAGS = $(PTHREAD_CFLAGS) AM_LDFLAGS = -version-number '$(ODPHELPER_LIBSO_VERSION)' diff --git a/helper/m4/configure.m4 b/helper/m4/configure.m4 index e67ca019e..36629c81e 100644 --- a/helper/m4/configure.m4 +++ b/helper/m4/configure.m4 @@ -1,3 +1,8 @@ +########################################################################## +# Include m4 files +########################################################################## +m4_include([helper/m4/libcli.m4]) + ########################################################################## # Enable/disable test-helper ########################################################################## @@ -42,20 +47,5 @@ AS_IF([test "x$enable_helper_debug_print" != "xno"], [ODPH_DEBUG_PRINT=1], AC_DEFINE_UNQUOTED([ODPH_DEBUG_PRINT], [$ODPH_DEBUG_PRINT], [Define to 1 to display helper debug information]) -######################################################################### -# If libcli is available, enable CLI helper -######################################################################### -helper_cli=no -AC_CHECK_HEADER(libcli.h, - [AC_CHECK_LIB(cli, cli_init, [helper_cli=yes], [], [-lcrypt])], - []) - -LIBCLI_LIBS="" -AS_IF([test "x$helper_cli" != "xno"], - [AC_DEFINE_UNQUOTED([ODPH_CLI], [1], [Define to 1 to enable CLI helper]) - LIBCLI_LIBS="-lcli -lcrypt"]) - -AC_SUBST([LIBCLI_LIBS]) - AC_CONFIG_FILES([helper/libodphelper.pc helper/test/Makefile]) diff --git a/helper/m4/libcli.m4 b/helper/m4/libcli.m4 new file mode 100644 index 000000000..6748cbb41 --- /dev/null +++ b/helper/m4/libcli.m4 @@ -0,0 +1,43 @@ +########################################################################## +# Set optional libcli path +########################################################################## +AC_ARG_WITH([libcli-path], + [AS_HELP_STRING([--with-libcli-path=DIR], + [path to libcli libs and headers [default=system]])], + [libcli_path_given=yes + LIBCLI_CPPFLAGS="-I$withval/include" + LIBCLI_LIBS="-L$withval/lib" + LIBCLI_RPATH="-R$withval/lib"], + []) + +########################################################################## +# Save and set temporary compilation flags +########################################################################## +OLD_CPPFLAGS=$CPPFLAGS +OLD_LIBS=$LIBS +CPPFLAGS="$LIBCLI_CPPFLAGS $CPPFLAGS" +LIBS="$LIBCLI_LIBS $LIBS" + +######################################################################### +# If libcli is available, enable CLI helper +######################################################################### +helper_cli=no +AC_CHECK_HEADER(libcli.h, + [AC_CHECK_LIB(cli, cli_init, [helper_cli=yes], [], [-lcrypt])], + [AS_IF([test "x$libcli_path_given" = "xyes"], + [AC_MSG_ERROR([libcli not found at the specified path (--with-libcli-path)])])]) + +AS_IF([test "x$helper_cli" != "xno"], + [AC_DEFINE_UNQUOTED([ODPH_CLI], [1], [Define to 1 to enable CLI helper]) + LIBCLI_LIBS="$LIBCLI_RPATH $LIBCLI_LIBS -lcli -lcrypt"], + [LIBCLI_CPPFLAGS="" + LIBCLI_LIBS=""]) + +########################################################################## +# Restore old saved variables +########################################################################## +LIBS=$OLD_LIBS +CPPFLAGS=$OLD_CPPFLAGS + +AC_SUBST([LIBCLI_CPPFLAGS]) +AC_SUBST([LIBCLI_LIBS]) -- cgit v1.2.3 From f9f29f9aad106bfd31b0e50ff5b886d9a7a7a5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Thu, 28 Jan 2021 20:53:23 +0200 Subject: helper: test: implement CLI helper test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test CLI helper by starting and stopping the ODP CLI server. Signed-off-by: Jere Leppänen Reviewed-by: Matias Elo --- helper/test/.gitignore | 1 + helper/test/Makefile.am | 5 ++++ helper/test/cli.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 helper/test/cli.c diff --git a/helper/test/.gitignore b/helper/test/.gitignore index 23fab7b30..e1e5ab7b2 100644 --- a/helper/test/.gitignore +++ b/helper/test/.gitignore @@ -1,6 +1,7 @@ *.trs *.log chksum +cli cuckootable iplookuptable odpthreads diff --git a/helper/test/Makefile.am b/helper/test/Makefile.am index ef3e2e370..400e7c080 100644 --- a/helper/test/Makefile.am +++ b/helper/test/Makefile.am @@ -19,6 +19,11 @@ linux_pthread_SOURCES = linux/pthread.c linux_process_SOURCES = linux/process.c endif +if helper_cli +EXECUTABLES += cli +cli_SOURCES = cli.c +endif + COMPILE_ONLY = odpthreads TESTSCRIPTS = odpthreads_as_processes \ diff --git a/helper/test/cli.c b/helper/test/cli.c new file mode 100644 index 000000000..ff3ea2f53 --- /dev/null +++ b/helper/test/cli.c @@ -0,0 +1,62 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +int main(int argc, char *argv[]) +{ + odp_instance_t instance; + odph_helper_options_t helper_options; + odp_init_t init_param; + + argc = odph_parse_options(argc, argv); + if (odph_options(&helper_options)) { + ODPH_ERR("Error: reading ODP helper options failed.\n"); + exit(EXIT_FAILURE); + } + + odp_init_param_init(&init_param); + init_param.mem_model = helper_options.mem_model; + + memset(&instance, 0, sizeof(instance)); + + if (odp_init_global(&instance, NULL, NULL)) { + ODPH_ERR("Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + ODPH_ERR("Error: ODP local init failed.\n"); + exit(EXIT_FAILURE); + } + + odph_cli_param_t cli_param; + + odph_cli_param_init(&cli_param); + + if (odph_cli_start(instance, &cli_param)) { + ODPH_ERR("Error: odph_cli_start() failed.\n"); + exit(EXIT_FAILURE); + } + + if (odph_cli_stop()) { + ODPH_ERR("Error: odph_cli_stop() failed.\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_local()) { + ODPH_ERR("Error: ODP local term failed.\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_global(instance)) { + ODPH_ERR("Error: ODP global term failed.\n"); + exit(EXIT_FAILURE); + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3 From fee7bbb8a1512c37c118605a09867476f3bbef77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Fri, 29 Jan 2021 13:26:03 +0200 Subject: example: add CLI helper example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This example shows how to start and stop ODP CLI using the CLI helper API functions. Signed-off-by: Jere Leppänen Reviewed-by: Matias Elo --- doc/application-api-guide/examples.dox | 5 + example/Makefile.am | 4 + example/cli/.gitignore | 3 + example/cli/Makefile.am | 31 ++++++ example/cli/odp_cli.c | 176 +++++++++++++++++++++++++++++++++ example/cli/odp_cli_run.sh | 9 ++ example/m4/configure.m4 | 1 + 7 files changed, 229 insertions(+) create mode 100644 example/cli/.gitignore create mode 100644 example/cli/Makefile.am create mode 100644 example/cli/odp_cli.c create mode 100755 example/cli/odp_cli_run.sh diff --git a/doc/application-api-guide/examples.dox b/doc/application-api-guide/examples.dox index 98e66d72b..18817cd63 100644 --- a/doc/application-api-guide/examples.dox +++ b/doc/application-api-guide/examples.dox @@ -9,6 +9,11 @@ * Classifier example application */ +/** + * @example odp_cli.c + * CLI example application + */ + /** * @example odp_debug.c * Debug example application diff --git a/example/Makefile.am b/example/Makefile.am index fc4623d1f..d6d242cf9 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -18,3 +18,7 @@ SUBDIRS = classifier \ if HAVE_DW_ATOMIC_CMP_EXC SUBDIRS += ipfragreass endif + +if helper_cli +SUBDIRS += cli +endif diff --git a/example/cli/.gitignore b/example/cli/.gitignore new file mode 100644 index 000000000..2a19d7a64 --- /dev/null +++ b/example/cli/.gitignore @@ -0,0 +1,3 @@ +odp_cli +*.log +*.trs diff --git a/example/cli/Makefile.am b/example/cli/Makefile.am new file mode 100644 index 000000000..0e97a09ed --- /dev/null +++ b/example/cli/Makefile.am @@ -0,0 +1,31 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_cli + +odp_cli_SOURCES = odp_cli.c + +if test_example +TESTS = odp_cli_run.sh +endif + +EXTRA_DIST = odp_cli_run.sh + +# If building out-of-tree, make check will not copy the scripts and data to the +# $(builddir) assuming that all commands are run locally. However this prevents +# running tests on a remote target using LOG_COMPILER. +# So copy all script and data files explicitly here. +all-local: + if [ "x$(srcdir)" != "x$(builddir)" ]; then \ + for f in $(EXTRA_DIST); do \ + if [ -e $(srcdir)/$$f ]; then \ + mkdir -p $(builddir)/$$(dirname $$f); \ + cp -f $(srcdir)/$$f $(builddir)/$$f; \ + fi \ + done \ + fi +clean-local: + if [ "x$(srcdir)" != "x$(builddir)" ]; then \ + for f in $(EXTRA_DIST); do \ + rm -f $(builddir)/$$f; \ + done \ + fi diff --git a/example/cli/odp_cli.c b/example/cli/odp_cli.c new file mode 100644 index 000000000..e3998129c --- /dev/null +++ b/example/cli/odp_cli.c @@ -0,0 +1,176 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * ODP CLI Helper Example + * + * This example shows how to start and stop ODP CLI using the CLI helper + * API functions. This example application can also be used to try out + * the CLI by connecting to a running application with a telnet client. + */ + +#include +#include + +#include +#include +#include + +typedef struct { + int time; + char *addr; + uint16_t port; +} options_t; + +static void usage(const char *prog) +{ + printf("\n" + "Usage: %s [options]\n" + "\n" + "OPTIONS:\n" + " -t, --time Keep CLI open for seconds. (default -1 (infinite))\n" + " -a, --address Bind listening socket to IP address .\n" + " -p, --port Bind listening socket to port .\n" + "\n" + "ODP helper defaults are used for address and port, if the options are\n" + "not given.\n" + "\n", + prog); +} + +static void parse_args(int argc, char *argv[], options_t *opt) +{ + static const struct option longopts[] = { + { "time", required_argument, NULL, 't' }, + { "address", required_argument, NULL, 'a' }, + { "port", required_argument, NULL, 'p' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } + }; + + static const char *shortopts = "+t:a:p:h"; + + while (1) { + int c = getopt_long(argc, argv, shortopts, longopts, NULL); + + if (c == -1) + break; /* No more options */ + + switch (c) { + case 't': + opt->time = atoi(optarg); + break; + case 'a': + opt->addr = optarg; + break; + case 'p': + opt->port = atoi(optarg); + break; + default: + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + } + } + + optind = 1; /* reset 'extern optind' from the getopt lib */ +} + +static volatile int shutdown_sig; + +static void sig_handler(int signo) +{ + (void)signo; + + shutdown_sig = 1; +} + +int main(int argc, char *argv[]) +{ + signal(SIGINT, sig_handler); + + odph_helper_options_t helper_options; + + /* Let helper collect its own arguments (e.g. --odph_proc) */ + argc = odph_parse_options(argc, argv); + if (odph_options(&helper_options)) { + ODPH_ERR("Error: reading ODP helper options failed.\n"); + exit(EXIT_FAILURE); + } + + odp_init_t init; + + odp_init_param_init(&init); + init.mem_model = helper_options.mem_model; + + options_t opt = { + .time = -1, + .addr = NULL, + .port = 0, + }; + + parse_args(argc, argv, &opt); + + /* Initialize ODP. */ + + odp_instance_t inst; + + if (odp_init_global(&inst, &init, NULL)) { + ODPH_ERR("Global init failed.\n"); + exit(EXIT_FAILURE); + } + + if (odp_init_local(inst, ODP_THREAD_CONTROL)) { + ODPH_ERR("Local init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Prepare CLI parameters. */ + + odph_cli_param_t cli_param; + + odph_cli_param_init(&cli_param); + + if (opt.addr) + cli_param.address = opt.addr; + + if (opt.port) + cli_param.port = opt.port; + + /* Start CLI server. */ + if (odph_cli_start(inst, &cli_param)) { + ODPH_ERR("CLI start failed.\n"); + exit(EXIT_FAILURE); + } + + printf("CLI server started on %s:%d\n", cli_param.address, cli_param.port); + + /* Wait for the given number of seconds. */ + for (int i = 0; (opt.time < 0 || i < opt.time) && !shutdown_sig; i++) + odp_time_wait_ns(ODP_TIME_SEC_IN_NS); + + printf("Stopping CLI server.\n"); + + /* Stop CLI server. */ + if (odph_cli_stop()) { + ODPH_ERR("CLI stop failed.\n"); + exit(EXIT_FAILURE); + } + + /* Terminate ODP. */ + + if (odp_term_local()) { + ODPH_ERR("Local term failed.\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_global(inst)) { + ODPH_ERR("Global term failed.\n"); + exit(EXIT_FAILURE); + } + + return 0; +} diff --git a/example/cli/odp_cli_run.sh b/example/cli/odp_cli_run.sh new file mode 100755 index 000000000..0dc00b793 --- /dev/null +++ b/example/cli/odp_cli_run.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# +# Copyright (c) 2021, Nokia +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +./odp_cli${EXEEXT} -t 2 diff --git a/example/m4/configure.m4 b/example/m4/configure.m4 index a1668e2b3..b02fd72a5 100644 --- a/example/m4/configure.m4 +++ b/example/m4/configure.m4 @@ -20,6 +20,7 @@ AC_ARG_ENABLE([test-example], AM_CONDITIONAL([test_example], [test x$test_example = xyes ]) AC_CONFIG_FILES([example/classifier/Makefile + example/cli/Makefile example/debug/Makefile example/generator/Makefile example/hello/Makefile -- cgit v1.2.3 From 075be21361eaf48d1f859a2808556dc74622a133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20Lepp=C3=A4nen?= Date: Mon, 22 Feb 2021 16:09:29 +0200 Subject: helper: increment library version to 1.0.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increment helper library version number to reflect the addition of CLI helper. Signed-off-by: Jere Leppänen Reviewed-by: Matias Elo --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 83b25b4eb..75ff1d235 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ AC_SUBST(ODP_VERSION_API_MINOR) ########################################################################## m4_define([odph_version_generation], [1]) m4_define([odph_version_major], [0]) -m4_define([odph_version_minor], [5]) +m4_define([odph_version_minor], [6]) m4_define([odph_version], [odph_version_generation.odph_version_major.odph_version_minor]) -- cgit v1.2.3 From a232ac2e2960ee0517db23d5f75a12afd2a0c215 Mon Sep 17 00:00:00 2001 From: Govindarajan Mohandoss Date: Wed, 9 Dec 2020 23:10:07 +0000 Subject: api: atomic: add 128 bit atomic apis Add 128 bit atomic compare-and-swap operations. Signed-off-by: Govindarajan Mohandoss Reviewed-by: Petri Savolainen --- include/odp/api/abi-default/atomic.h | 26 +++++++ include/odp/api/spec/atomic.h | 144 +++++++++++++++++++++++++++++++++-- include/odp/api/spec/std_types.h | 23 ++++++ 3 files changed, 186 insertions(+), 7 deletions(-) diff --git a/include/odp/api/abi-default/atomic.h b/include/odp/api/abi-default/atomic.h index e37f254fc..a58f42b8f 100644 --- a/include/odp/api/abi-default/atomic.h +++ b/include/odp/api/abi-default/atomic.h @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2021, ARM Limited * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -59,6 +60,31 @@ typedef struct ODP_ALIGNED(sizeof(uint64_t)) odp_atomic_u64_s { #endif +#ifdef _ODP_LOCK_FREE_128BIT_ATOMICS + +/** + * @internal + * Atomic 128-bit unsigned integer + */ +typedef struct ODP_ALIGNED(sizeof(odp_u128_t)) odp_atomic_u128_s { + odp_u128_t v; /**< Actual storage for the atomic variable */ +} odp_atomic_u128_t; + +#else + +/** + * @internal + * Atomic 128-bit unsigned integer + */ +typedef struct ODP_ALIGNED(sizeof(odp_u128_t)) odp_atomic_u128_s { + odp_u128_t v; /**< Actual storage for the atomic variable */ + /* Some architectures do not support lock-free operations on 128-bit + * data types. We use a spin lock to ensure atomicity. */ + char lock; /**< Spin lock (if needed) used to ensure atomic access */ +} odp_atomic_u128_t; + +#endif + #ifdef __cplusplus } #endif diff --git a/include/odp/api/spec/atomic.h b/include/odp/api/spec/atomic.h index f1e1818eb..15573b8b6 100644 --- a/include/odp/api/spec/atomic.h +++ b/include/odp/api/spec/atomic.h @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2021, ARM Limited * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -25,13 +26,13 @@ extern "C" { * @details * Atomic integers using relaxed memory ordering * - * Atomic integer types (odp_atomic_u32_t and odp_atomic_u64_t) can be used to - * implement e.g. shared counters. If not otherwise documented, operations in - * this API are implemented using RELAXED memory ordering (see memory - * order descriptions in the C11 specification). Relaxed operations do not - * provide synchronization or ordering for other memory accesses (initiated - * before or after the operation), only atomicity of the operation itself is - * guaranteed. + * Atomic integer types (odp_atomic_u32_t, odp_atomic_u64_t and + * odp_atomic_u128_t) can be used to implement e.g. shared counters. If not + * otherwise documented, operations in this API are implemented using + * RELAXED memory ordering (see memory order descriptions in + * the C11 specification). Relaxed operations do not provide synchronization or + * ordering for other memory accesses (initiated before or after the operation), + * only atomicity of the operation itself is guaranteed. * * Operations with non-relaxed memory ordering * @@ -54,6 +55,9 @@ extern "C" { */ /** + * @typedef odp_atomic_u128_t + * Atomic 128-bit unsigned integer + * * @typedef odp_atomic_u64_t * Atomic 64-bit unsigned integer * @@ -372,6 +376,58 @@ int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val, */ uint64_t odp_atomic_xchg_u64(odp_atomic_u64_t *atom, uint64_t new_val); +/* + * 128-bit operations in RELAXED memory ordering + * -------------------------------------------- + */ + +/** + * Initialize atomic odp_u128_t variable + * + * Initializes the atomic variable with 'val'. This operation is not atomic. + * Application must ensure that there's no race condition while initializing + * the variable. + * + * @param atom Pointer to atomic variable + * @param val Value to initialize the variable with + */ +void odp_atomic_init_u128(odp_atomic_u128_t *atom, odp_u128_t val); + +/** + * Load value of atomic odp_u128_t variable + * + * @param atom Pointer to atomic variable + * + * @return Value of the variable + */ +odp_u128_t odp_atomic_load_u128(odp_atomic_u128_t *atom); + +/** + * Store value to atomic odp_u128_t variable + * + * @param atom Pointer to atomic variable + * @param val Value to store in the variable + */ +void odp_atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t val); + +/** + * Compare and swap atomic odp_u128_t variable + * + * Compares value of atomic variable to the value pointed by 'old_val'. + * If values are equal, the operation writes 'new_val' into the atomic variable + * and returns success. If they are not equal, the operation writes current + * value of atomic variable into 'old_val' and returns failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, + odp_u128_t new_val); + /* * 32-bit operations in non-RELAXED memory ordering * ------------------------------------------------ @@ -622,6 +678,80 @@ typedef union odp_atomic_op_t { */ int odp_atomic_lock_free_u64(odp_atomic_op_t *atomic_op); +/* + * 128-bit operations in non-RELAXED memory ordering + * ------------------------------------------------ + */ + +/** + * Compare and swap atomic odp_u128_t variable using ACQUIRE memory ordering + * + * Otherwise identical to odp_atomic_cas_u128() but ensures ACQUIRE memory + * ordering on success. Memory ordering is RELAXED on failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_acq_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, + odp_u128_t new_val); + +/** + * Compare and swap atomic odp_u128_t variable using RELEASE memory ordering + * + * Otherwise identical to odp_atomic_cas_u128() but ensures RELEASE memory + * ordering on success. Memory ordering is RELAXED on failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_rel_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, + odp_u128_t new_val); + +/** + * Compare and swap atomic odp_u128_t variable using ACQUIRE-and-RELEASE memory + * ordering + * + * Otherwise identical to odp_atomic_cas_u128() but ensures ACQUIRE-and-RELEASE + * memory ordering on success. Memory ordering is RELAXED on failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_acq_rel_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, + odp_u128_t new_val); + +/** + * Query which atomic odp_atomic_u128_t operations are lock-free + * + * Lock-free implementations have higher performance and scale better than + * implementations using locks. + * + * Init operations (e.g. odp_atomic_init_u128()) are not atomic. This function + * clears the op.init bit but will never set it to one. + * + * Note: 128-bit atomic API includes only init, load, store and CAS operations. + * + * @param atomic_op Pointer to atomic operation structure for storing + * operation flags. All bits are initialized to zero during + * the operation. The parameter is ignored when NULL. + * @retval 0 None of the 128-bit atomic operations are lock-free + * @retval 1 Some of the 128-bit atomic operations are lock-free + * @retval 2 All 128-bit atomic operations are lock-free + */ +int odp_atomic_lock_free_u128(odp_atomic_op_t *atomic_op); + /** * @} */ diff --git a/include/odp/api/spec/std_types.h b/include/odp/api/spec/std_types.h index 6e2617b4e..bf3eb77a6 100644 --- a/include/odp/api/spec/std_types.h +++ b/include/odp/api/spec/std_types.h @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2021, ARM Limited * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -50,6 +51,28 @@ typedef uint32_t odp_una_u32_t ODP_ALIGNED(1); /** Unaligned uint64_t type */ typedef uint64_t odp_una_u64_t ODP_ALIGNED(1); +/** + * @typedef odp_u128_t + * 128-bit unsigned integer structure + */ + +/** + * 128-bit unsigned integer structure + */ +typedef struct ODP_ALIGNED(16) odp_u128_s { + /** 128 bits in various sizes */ + union { + /** 128 bits as uint64_t words */ + uint64_t u64[2]; + /** 128 bits as uint32_t words */ + uint32_t u32[4]; + /** 128 bits as uint16_t words */ + uint16_t u16[8]; + /** 128 bits as bytes */ + uint8_t u8[16]; + }; +} odp_u128_t; + /** * @} */ -- cgit v1.2.3 From 418e577a470f773035880a30d7fe5f6cec1b42ba Mon Sep 17 00:00:00 2001 From: Govindarajan Mohandoss Date: Fri, 11 Dec 2020 22:49:20 +0000 Subject: linux-gen: atomic: add 128 bit atomic apis Add 128 bit atomic compare-and-swap operations. Signed-off-by: Govindarajan Mohandoss Reviewed-by: Petri Savolainen Reviewed-by: Matias Elo Tested-by: Malvika Gupta --- platform/linux-generic/Makefile.am | 3 +- .../arch/aarch64/odp/api/abi/atomic.h | 12 + platform/linux-generic/arch/aarch64/odp_atomic.h | 53 +++- .../linux-generic/include-abi/odp/api/abi/atomic.h | 25 ++ platform/linux-generic/odp_atomic.c | 280 +++++++++++++++++++++ 5 files changed, 370 insertions(+), 3 deletions(-) create mode 100644 platform/linux-generic/arch/aarch64/odp/api/abi/atomic.h diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 00ea764de..1d9a3bbdb 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -290,7 +290,8 @@ odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ arch/default/odp/api/abi/cpu_time.h \ arch/aarch64/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT -odpapiabiarchinclude_HEADERS += arch/aarch64/odp/api/abi/cpu.h +odpapiabiarchinclude_HEADERS += arch/aarch64/odp/api/abi/atomic.h \ + arch/aarch64/odp/api/abi/cpu.h endif noinst_HEADERS += arch/aarch64/odp_atomic.h \ arch/aarch64/odp_cpu.h \ diff --git a/platform/linux-generic/arch/aarch64/odp/api/abi/atomic.h b/platform/linux-generic/arch/aarch64/odp/api/abi/atomic.h new file mode 100644 index 000000000..d1dbf36b8 --- /dev/null +++ b/platform/linux-generic/arch/aarch64/odp/api/abi/atomic.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2021, ARM Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef __ARM_FEATURE_ATOMICS +#define _ODP_LOCK_FREE_128BIT_ATOMICS +#endif + +#include + diff --git a/platform/linux-generic/arch/aarch64/odp_atomic.h b/platform/linux-generic/arch/aarch64/odp_atomic.h index 8a0e7ce2b..dbeccebde 100644 --- a/platform/linux-generic/arch/aarch64/odp_atomic.h +++ b/platform/linux-generic/arch/aarch64/odp_atomic.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2017, ARM Limited. All rights reserved. - * +/* Copyright (c) 2017-2021, ARM Limited * Copyright (c) 2017-2018, Linaro Limited * All rights reserved. * @@ -218,4 +217,54 @@ static inline __int128 __lockfree_load_16(__int128 *var, int mo) return old; } +#ifdef _ODP_LOCK_FREE_128BIT_ATOMICS + +/** + * @internal + * Helper macro for lockless atomic CAS operations on 128-bit integers + * @param[in,out] atom Pointer to the 128-bit atomic variable + * @param oper CAS operation + * @param old_val Old value + * @param new_val New value to be swapped + * @return 1 for success and 0 for fail + */ +#define ATOMIC_CAS_OP_128(atom, oper, old_val, new_val, val) \ +({ \ + odp_u128_t _val; \ + odp_atomic_u128_t *_atom = atom; \ + odp_u128_t *_old_val = old_val; \ + odp_u128_t _new_val = new_val; \ + odp_u128_t *ptr = (odp_u128_t *)(_atom); \ + register uint64_t old0 __asm__ ("x0"); \ + register uint64_t old1 __asm__ ("x1"); \ + register uint64_t new0 __asm__ ("x2"); \ + register uint64_t new1 __asm__ ("x3"); \ + old0 = (uint64_t)(_old_val)->u64[0]; \ + old1 = (uint64_t)(_old_val)->u64[1]; \ + new0 = (uint64_t)(_new_val).u64[0]; \ + new1 = (uint64_t)(_new_val).u64[1]; \ + __asm__ volatile(oper " %[old0], %[old1], %[new0], %[new1], [%[ptr]]" \ + : [old0] "+r" (old0), [old1] "+r" (old1) \ + : [new0] "r" (new0), [new1] "r" (new1), \ + [ptr] "r" (ptr) \ + : "memory"); \ + _val.u64[0] = old0; \ + _val.u64[1] = old1; \ + val = _val; \ +}) + +#define ATOMIC_CAS_OP_128_NO_ORDER(atom, old_value, new_value, val) \ + ATOMIC_CAS_OP_128(atom, "casp", old_value, new_value, val) + +#define ATOMIC_CAS_OP_128_ACQ(atom, old_value, new_value, val) \ + ATOMIC_CAS_OP_128(atom, "caspa", old_value, new_value, val) + +#define ATOMIC_CAS_OP_128_REL(atom, old_value, new_value, val) \ + ATOMIC_CAS_OP_128(atom, "caspl", old_value, new_value, val) + +#define ATOMIC_CAS_OP_128_ACQ_REL(atom, old_value, new_value, val) \ + ATOMIC_CAS_OP_128(atom, "caspal", old_value, new_value, val) + +#endif + #endif /* PLATFORM_LINUXGENERIC_ARCH_ARM_ODP_ATOMIC_H */ diff --git a/platform/linux-generic/include-abi/odp/api/abi/atomic.h b/platform/linux-generic/include-abi/odp/api/abi/atomic.h index 955b99370..13c12a79f 100644 --- a/platform/linux-generic/include-abi/odp/api/abi/atomic.h +++ b/platform/linux-generic/include-abi/odp/api/abi/atomic.h @@ -55,6 +55,31 @@ typedef struct ODP_ALIGNED(sizeof(uint64_t)) odp_atomic_u64_s { #endif +#ifdef _ODP_LOCK_FREE_128BIT_ATOMICS + +/** + * @internal + * Atomic 128-bit unsigned integer + */ +typedef struct ODP_ALIGNED(sizeof(odp_u128_t)) odp_atomic_u128_s { + odp_u128_t v; /**< Actual storage for the atomic variable */ +} odp_atomic_u128_t; + +#else + +/** + * @internal + * Atomic 128-bit unsigned integer + */ +typedef struct ODP_ALIGNED(sizeof(odp_u128_t)) odp_atomic_u128_s { + odp_u128_t v; /**< Actual storage for the atomic variable */ + /* Some architectures do not support lock-free operations on 128-bit + * data types. We use a spin lock to ensure atomicity. */ + char lock; /**< Spin lock (if needed) used to ensure atomic access */ +} odp_atomic_u128_t; + +#endif + /** @ingroup odp_atomic * @{ */ diff --git a/platform/linux-generic/odp_atomic.c b/platform/linux-generic/odp_atomic.c index 32ddc95c2..59253c645 100644 --- a/platform/linux-generic/odp_atomic.c +++ b/platform/linux-generic/odp_atomic.c @@ -1,10 +1,12 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2021, ARM Limited * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include +#include int odp_atomic_lock_free_u64(odp_atomic_op_t *atomic_op) { @@ -24,3 +26,281 @@ int odp_atomic_lock_free_u64(odp_atomic_op_t *atomic_op) return 2; #endif } + +int odp_atomic_lock_free_u128(odp_atomic_op_t *atomic_op) +{ +#ifdef _ODP_LOCK_FREE_128BIT_ATOMICS + if (atomic_op) { + atomic_op->all_bits = 0; + atomic_op->op.load = 1; + atomic_op->op.store = 1; + atomic_op->op.cas = 1; + } + + return 2; +#else + /* All operations have locks */ + if (atomic_op) + atomic_op->all_bits = 0; + + return 0; +#endif +} + +#ifdef _ODP_LOCK_FREE_128BIT_ATOMICS + +static void __atomic_init_u128(odp_atomic_u128_t *atom, odp_u128_t new_val) +{ + odp_u128_t old, val; + + old = atom->v; + + while (1) { + ATOMIC_CAS_OP_128_NO_ORDER(atom, &old, new_val, val); + + if ((val.u64[0] == old.u64[0]) && (val.u64[1] == old.u64[1])) + return; + + old = val; + } +} + +static odp_u128_t __atomic_load_u128(odp_atomic_u128_t *atom) +{ + odp_u128_t val, exp; + + exp.u64[0] = 0; + exp.u64[1] = 0; + ATOMIC_CAS_OP_128_NO_ORDER(atom, &exp, exp, val); + return val; +} + +static void __atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t new_val) +{ + odp_u128_t old, val; + + old = atom->v; + + while (1) { + ATOMIC_CAS_OP_128_NO_ORDER(atom, &old, new_val, val); + + if ((val.u64[0] == old.u64[0]) && (val.u64[1] == old.u64[1])) + return; + + old = val; + } +} + +static int __atomic_cas_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + int ret = 0; + odp_u128_t val; + + ATOMIC_CAS_OP_128_NO_ORDER(atom, old_val, new_val, val); + + if ((val.u64[0] == old_val->u64[0]) && (val.u64[1] == old_val->u64[1])) + ret = 1; + + old_val->u64[0] = val.u64[0]; + old_val->u64[1] = val.u64[1]; + + return ret; +} + +static int __atomic_cas_acq_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + int ret = 0; + odp_u128_t val; + + ATOMIC_CAS_OP_128_ACQ(atom, old_val, new_val, val); + + if ((val.u64[0] == old_val->u64[0]) && (val.u64[1] == old_val->u64[1])) + ret = 1; + + old_val->u64[0] = val.u64[0]; + old_val->u64[1] = val.u64[1]; + + return ret; +} + +static int __atomic_cas_rel_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + int ret = 0; + odp_u128_t val; + + ATOMIC_CAS_OP_128_REL(atom, old_val, new_val, val); + + if ((val.u64[0] == old_val->u64[0]) && (val.u64[1] == old_val->u64[1])) + ret = 1; + + old_val->u64[0] = val.u64[0]; + old_val->u64[1] = val.u64[1]; + + return ret; +} + +static int __atomic_cas_acq_rel_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, + odp_u128_t new_val) +{ + int ret = 0; + odp_u128_t val; + + ATOMIC_CAS_OP_128_ACQ_REL(atom, old_val, new_val, val); + + if ((val.u64[0] == old_val->u64[0]) && (val.u64[1] == old_val->u64[1])) + ret = 1; + + old_val->u64[0] = val.u64[0]; + old_val->u64[1] = val.u64[1]; + + return ret; +} + +#else /* Locked version */ + +/** + * @internal + * 128 bit store operation expression for the ATOMIC_OP macro + */ +#define ATOMIC_STORE_OP_128(new_val) \ +({ \ + (_atom)->v = (new_val); \ +}) + +/** + * @internal + * 128 bit CAS operation expression for the ATOMIC_OP macro + */ +#define ATOMIC_CAS_OP_128(ret_ptr, old_val, new_val) \ +({ \ + int *_ret_ptr = ret_ptr; \ + odp_u128_t *_old_val = old_val; \ + odp_u128_t _new_val = new_val; \ + if (((_atom)->v.u64[0] == (_old_val)->u64[0]) && \ + ((_atom)->v.u64[1] == (_old_val)->u64[1])) { \ + (_atom)->v = (_new_val); \ + *(_ret_ptr) = 1; \ + } else { \ + *(_ret_ptr) = 0; \ + } \ +}) + +/** + * @internal + * Helper macro for lock-based atomic operations on 128-bit integers + * @param[in,out] atom Pointer to the 128-bit atomic variable + * @param expr Expression used update the variable. + * @return The old value of the variable. + */ +#define ATOMIC_OP_128(atom, expr) \ +({ \ + odp_u128_t _old_val; \ + odp_atomic_u128_t *_atom = atom; \ + /* Loop while lock is already taken, stop when lock becomes clear */ \ + while (__atomic_test_and_set(&(_atom)->lock, __ATOMIC_ACQUIRE)) \ + (void)0; \ + _old_val = (_atom)->v; \ + (expr); /* Perform whatever update is desired */ \ + __atomic_clear(&(_atom)->lock, __ATOMIC_RELEASE); \ + _old_val; /* Return old value */ \ +}) + +static void __atomic_init_u128(odp_atomic_u128_t *atom, odp_u128_t val) +{ + atom->lock = 0; + ATOMIC_OP_128(atom, ATOMIC_STORE_OP_128(val)); +} + +static odp_u128_t __atomic_load_u128(odp_atomic_u128_t *atom) +{ + return ATOMIC_OP_128(atom, (void)0); +} + +static void __atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t val) +{ + ATOMIC_OP_128(atom, ATOMIC_STORE_OP_128(val)); +} + +static int __atomic_cas_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + int ret; + *old_val = ATOMIC_OP_128(atom, ATOMIC_CAS_OP_128(&ret, old_val, + new_val)); + return ret; +} + +static int __atomic_cas_acq_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, + odp_u128_t new_val) +{ + int ret; + *old_val = ATOMIC_OP_128(atom, ATOMIC_CAS_OP_128(&ret, old_val, + new_val)); + return ret; +} + +static int __atomic_cas_rel_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, + odp_u128_t new_val) +{ + int ret; + *old_val = ATOMIC_OP_128(atom, ATOMIC_CAS_OP_128(&ret, old_val, + new_val)); + return ret; +} + +static int __atomic_cas_acq_rel_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, + odp_u128_t new_val) +{ + int ret; + *old_val = ATOMIC_OP_128(atom, ATOMIC_CAS_OP_128(&ret, old_val, + new_val)); + return ret; +} + +#endif + +void odp_atomic_init_u128(odp_atomic_u128_t *atom, odp_u128_t val) +{ + __atomic_init_u128(atom, val); +} + +odp_u128_t odp_atomic_load_u128(odp_atomic_u128_t *atom) +{ + return __atomic_load_u128(atom); +} + +void odp_atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t val) +{ + __atomic_store_u128(atom, val); +} + +int odp_atomic_cas_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + return __atomic_cas_u128(atom, old_val, new_val); +} + +int odp_atomic_cas_acq_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + return __atomic_cas_acq_u128(atom, old_val, new_val); +} + +int odp_atomic_cas_rel_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + return __atomic_cas_rel_u128(atom, old_val, new_val); +} + +int odp_atomic_cas_acq_rel_u128(odp_atomic_u128_t *atom, + odp_u128_t *old_val, odp_u128_t new_val) +{ + return __atomic_cas_acq_rel_u128(atom, old_val, new_val); +} -- cgit v1.2.3 From 9d0f8d91ad8996fe8d7b4cfdc143442d2c43a5db Mon Sep 17 00:00:00 2001 From: Malvika Gupta Date: Wed, 27 Jan 2021 00:30:35 +0000 Subject: validation: atomic: add test cases for 128-bit atomic operations Test cases for 128-bit atomic operations have been added. Signed-off-by: Malvika Gupta Reviewed-by: Honnappa Nagarahalli Reviewed-by: Govindarajan Mohandoss Reviewed-by: Matias Elo Reviewed-by: Petri Savolainen --- test/validation/api/atomic/atomic.c | 258 ++++++++++++++++++++++++++++++------ 1 file changed, 215 insertions(+), 43 deletions(-) diff --git a/test/validation/api/atomic/atomic.c b/test/validation/api/atomic/atomic.c index 36484295f..907624bb0 100644 --- a/test/validation/api/atomic/atomic.c +++ b/test/validation/api/atomic/atomic.c @@ -28,11 +28,13 @@ #define CHECK_MAX_MIN (1 << 0) #define CHECK_XCHG (1 << 2) +#define CHECK_CAS_128 (1 << 4) typedef __volatile uint32_t volatile_u32_t; typedef __volatile uint64_t volatile_u64_t; typedef struct { + odp_atomic_u128_t a128u; odp_atomic_u64_t a64u; odp_atomic_u64_t a64u_min; odp_atomic_u64_t a64u_max; @@ -489,6 +491,90 @@ static void test_atomic_non_relaxed_64(void) } } +static void test_atomic_relaxed_128(void) +{ + int i, ret; + odp_u128_t old, new; + odp_atomic_u128_t *a128u = &global_mem->a128u; + + odp_barrier_wait(&global_mem->global_barrier); + + for (i = 0; i < CNT; i++) { + old = odp_atomic_load_u128(a128u); + + do { + new.u64[0] = old.u64[0] + 2; + new.u64[1] = old.u64[1] + 1; + + ret = odp_atomic_cas_u128(a128u, &old, new); + + } while (ret == 0); + } +} + +static void test_atomic_non_relaxed_128_acq(void) +{ + int i, ret; + odp_u128_t old, new; + odp_atomic_u128_t *a128u = &global_mem->a128u; + + odp_barrier_wait(&global_mem->global_barrier); + + for (i = 0; i < CNT; i++) { + old = odp_atomic_load_u128(a128u); + + do { + new.u64[0] = old.u64[0] + 2; + new.u64[1] = old.u64[1] + 1; + + ret = odp_atomic_cas_acq_u128(a128u, &old, new); + + } while (ret == 0); + } +} + +static void test_atomic_non_relaxed_128_rel(void) +{ + int i, ret; + odp_u128_t old, new; + odp_atomic_u128_t *a128u = &global_mem->a128u; + + odp_barrier_wait(&global_mem->global_barrier); + + for (i = 0; i < CNT; i++) { + old = odp_atomic_load_u128(a128u); + + do { + new.u64[0] = old.u64[0] + 2; + new.u64[1] = old.u64[1] + 1; + + ret = odp_atomic_cas_rel_u128(a128u, &old, new); + + } while (ret == 0); + } +} + +static void test_atomic_non_relaxed_128_acq_rel(void) +{ + int i, ret; + odp_u128_t old, new; + odp_atomic_u128_t *a128u = &global_mem->a128u; + + odp_barrier_wait(&global_mem->global_barrier); + + for (i = 0; i < CNT; i++) { + old = odp_atomic_load_u128(a128u); + + do { + new.u64[0] = old.u64[0] + 2; + new.u64[1] = old.u64[1] + 1; + + ret = odp_atomic_cas_acq_rel_u128(a128u, &old, new); + + } while (ret == 0); + } +} + static void test_atomic_inc_dec_32(void) { test_atomic_inc_32(); @@ -561,6 +647,14 @@ static void test_atomic_cas_inc_dec_64(void) test_atomic_cas_dec_64(); } +static void test_atomic_cas_inc_128(void) +{ + test_atomic_relaxed_128(); + test_atomic_non_relaxed_128_acq(); + test_atomic_non_relaxed_128_rel(); + test_atomic_non_relaxed_128_acq_rel(); +} + static void test_atomic_init(void) { odp_atomic_init_u32(&global_mem->a32u, 0); @@ -571,6 +665,12 @@ static void test_atomic_init(void) odp_atomic_init_u64(&global_mem->a64u_max, 0); odp_atomic_init_u32(&global_mem->a32u_xchg, 0); odp_atomic_init_u64(&global_mem->a64u_xchg, 0); + + odp_u128_t a128u_tmp; + + a128u_tmp.u64[0] = 0; + a128u_tmp.u64[1] = 0; + odp_atomic_init_u128(&global_mem->a128u, a128u_tmp); } static void test_atomic_store(void) @@ -583,6 +683,12 @@ static void test_atomic_store(void) odp_atomic_store_u64(&global_mem->a64u_max, U64_INIT_VAL); odp_atomic_store_u32(&global_mem->a32u_xchg, U32_INIT_VAL); odp_atomic_store_u64(&global_mem->a64u_xchg, U64_INIT_VAL); + + odp_u128_t a128u_tmp; + + a128u_tmp.u64[0] = U64_INIT_VAL; + a128u_tmp.u64[1] = U64_INIT_VAL; + odp_atomic_store_u128(&global_mem->a128u, a128u_tmp); } static void test_atomic_validate(int check) @@ -590,6 +696,20 @@ static void test_atomic_validate(int check) CU_ASSERT(U32_INIT_VAL == odp_atomic_load_u32(&global_mem->a32u)); CU_ASSERT(U64_INIT_VAL == odp_atomic_load_u64(&global_mem->a64u)); + odp_u128_t a128u_tmp; + + a128u_tmp = odp_atomic_load_u128(&global_mem->a128u); + + if (check & CHECK_CAS_128) { + uint64_t iterations = 0; + + iterations = a128u_tmp.u64[0] - a128u_tmp.u64[1]; + CU_ASSERT(iterations == 4 * CNT * global_mem->g_num_threads); + } else { + CU_ASSERT(U64_INIT_VAL == a128u_tmp.u64[0]); + CU_ASSERT(U64_INIT_VAL == a128u_tmp.u64[1]); + } + if (check & CHECK_MAX_MIN) { CU_ASSERT(odp_atomic_load_u32(&global_mem->a32u_max) > odp_atomic_load_u32(&global_mem->a32u_min)); @@ -763,6 +883,7 @@ static int test_atomic_cas_inc_dec_thread(void *arg UNUSED) per_thread_mem = thread_init(); test_atomic_cas_inc_dec_32(); test_atomic_cas_inc_dec_64(); + test_atomic_cas_inc_128(); thread_finalize(per_thread_mem); @@ -807,51 +928,9 @@ static void test_atomic_functional(int func_ptr(void *), int check) test_atomic_validate(check); } -static void atomic_test_atomic_inc_dec(void) -{ - test_atomic_functional(test_atomic_inc_dec_thread, 0); -} - -static void atomic_test_atomic_add_sub(void) -{ - test_atomic_functional(test_atomic_add_sub_thread, 0); -} - -static void atomic_test_atomic_fetch_inc_dec(void) -{ - test_atomic_functional(test_atomic_fetch_inc_dec_thread, 0); -} - -static void atomic_test_atomic_fetch_add_sub(void) -{ - test_atomic_functional(test_atomic_fetch_add_sub_thread, 0); -} - -static void atomic_test_atomic_max_min(void) -{ - test_atomic_functional(test_atomic_max_min_thread, CHECK_MAX_MIN); -} - -static void atomic_test_atomic_cas_inc_dec(void) -{ - test_atomic_functional(test_atomic_cas_inc_dec_thread, 0); -} - -static void atomic_test_atomic_xchg(void) -{ - test_atomic_functional(test_atomic_xchg_thread, CHECK_XCHG); -} - -static void atomic_test_atomic_non_relaxed(void) -{ - test_atomic_functional(test_atomic_non_relaxed_thread, - CHECK_MAX_MIN | CHECK_XCHG); -} - -static void atomic_test_atomic_op_lock_free(void) +static void test_atomic_op_lock_free_set(void) { odp_atomic_op_t atomic_op; - int ret_null, ret; memset(&atomic_op, 0xff, sizeof(odp_atomic_op_t)); atomic_op.all_bits = 0; @@ -897,6 +976,12 @@ static void atomic_test_atomic_op_lock_free(void) CU_ASSERT(atomic_op.all_bits != 0); atomic_op.op.dec = 0; CU_ASSERT(atomic_op.all_bits == 0); +} + +static void test_atomic_op_lock_free_64(void) +{ + odp_atomic_op_t atomic_op; + int ret_null, ret; memset(&atomic_op, 0xff, sizeof(odp_atomic_op_t)); ret = odp_atomic_lock_free_u64(&atomic_op); @@ -954,6 +1039,93 @@ static void atomic_test_atomic_op_lock_free(void) } } +static void test_atomic_op_lock_free_128(void) +{ + odp_atomic_op_t atomic_op; + int ret_null, ret; + + memset(&atomic_op, 0xff, sizeof(odp_atomic_op_t)); + ret = odp_atomic_lock_free_u128(&atomic_op); + ret_null = odp_atomic_lock_free_u128(NULL); + + CU_ASSERT(ret == ret_null); + + /* Init operation is not atomic by the spec. Call to + * odp_atomic_lock_free_u128() zeros it but never sets it. */ + + if (ret == 0) { + /* none are lock free */ + CU_ASSERT(atomic_op.all_bits == 0); + CU_ASSERT(atomic_op.op.init == 0); + CU_ASSERT(atomic_op.op.load == 0); + CU_ASSERT(atomic_op.op.store == 0); + CU_ASSERT(atomic_op.op.cas == 0); + } + + if (ret == 1) { + /* some are lock free */ + CU_ASSERT(atomic_op.all_bits != 0); + CU_ASSERT(atomic_op.op.init == 0); + } + + if (ret == 2) { + /* all are lock free */ + CU_ASSERT(atomic_op.all_bits != 0); + CU_ASSERT(atomic_op.op.init == 0); + CU_ASSERT(atomic_op.op.load == 1); + CU_ASSERT(atomic_op.op.store == 1); + CU_ASSERT(atomic_op.op.cas == 1); + } +} + +static void atomic_test_atomic_inc_dec(void) +{ + test_atomic_functional(test_atomic_inc_dec_thread, 0); +} + +static void atomic_test_atomic_add_sub(void) +{ + test_atomic_functional(test_atomic_add_sub_thread, 0); +} + +static void atomic_test_atomic_fetch_inc_dec(void) +{ + test_atomic_functional(test_atomic_fetch_inc_dec_thread, 0); +} + +static void atomic_test_atomic_fetch_add_sub(void) +{ + test_atomic_functional(test_atomic_fetch_add_sub_thread, 0); +} + +static void atomic_test_atomic_max_min(void) +{ + test_atomic_functional(test_atomic_max_min_thread, CHECK_MAX_MIN); +} + +static void atomic_test_atomic_cas_inc_dec(void) +{ + test_atomic_functional(test_atomic_cas_inc_dec_thread, CHECK_CAS_128); +} + +static void atomic_test_atomic_xchg(void) +{ + test_atomic_functional(test_atomic_xchg_thread, CHECK_XCHG); +} + +static void atomic_test_atomic_non_relaxed(void) +{ + test_atomic_functional(test_atomic_non_relaxed_thread, + CHECK_MAX_MIN | CHECK_XCHG); +} + +static void atomic_test_atomic_op_lock_free(void) +{ + test_atomic_op_lock_free_set(); + test_atomic_op_lock_free_64(); + test_atomic_op_lock_free_128(); +} + odp_testinfo_t atomic_suite_atomic[] = { ODP_TEST_INFO(atomic_test_atomic_inc_dec), ODP_TEST_INFO(atomic_test_atomic_add_sub), -- cgit v1.2.3 From 2344d43c96721d73b0f0ee5aa649e444363e0a8f Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Tue, 9 Feb 2021 18:10:32 +0200 Subject: api: atomic: CAS operations are strong type Current specification of CAS operation hints that the operation cannot fail spuriously. Specify this more tightly and use keyword "strong", which is used also in C standard (see e.g. atomic_compare_exchange_strong()). Signed-off-by: Petri Savolainen Reviewed-by: Jerin Jacob Reviewed-by: Matias Elo --- include/odp/api/spec/atomic.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/include/odp/api/spec/atomic.h b/include/odp/api/spec/atomic.h index 15573b8b6..a77527e85 100644 --- a/include/odp/api/spec/atomic.h +++ b/include/odp/api/spec/atomic.h @@ -193,9 +193,10 @@ void odp_atomic_min_u32(odp_atomic_u32_t *atom, uint32_t new_min); * Compare and swap atomic uint32 variable * * Compares value of atomic variable to the value pointed by 'old_val'. - * If values are equal, the operation writes 'new_val' into the atomic variable - * and returns success. If they are not equal, the operation writes current - * value of atomic variable into 'old_val' and returns failure. + * If the values are equal, the operation writes 'new_val' into the atomic variable + * and returns success. The operation returns failure only when the values are + * not equal (strong CAS operation). The current value of atomic variable is written + * into 'old_val' on failure. * * @param atom Pointer to atomic variable * @param[in,out] old_val Pointer to the old value of the atomic variable. @@ -203,10 +204,8 @@ void odp_atomic_min_u32(odp_atomic_u32_t *atom, uint32_t new_min); * @param new_val New value to be written into the atomic variable * * @return 0 on failure, !0 on success - * */ -int odp_atomic_cas_u32(odp_atomic_u32_t *atom, uint32_t *old_val, - uint32_t new_val); +int odp_atomic_cas_u32(odp_atomic_u32_t *atom, uint32_t *old_val, uint32_t new_val); /** * Exchange value of atomic uint32 variable @@ -349,9 +348,10 @@ void odp_atomic_min_u64(odp_atomic_u64_t *atom, uint64_t new_min); * Compare and swap atomic uint64 variable * * Compares value of atomic variable to the value pointed by 'old_val'. - * If values are equal, the operation writes 'new_val' into the atomic variable - * and returns success. If they are not equal, the operation writes current - * value of atomic variable into 'old_val' and returns failure. + * If the values are equal, the operation writes 'new_val' into the atomic variable + * and returns success. The operation returns failure only when the values are + * not equal (strong CAS operation). The current value of atomic variable is written + * into 'old_val' on failure. * * @param atom Pointer to atomic variable * @param[in,out] old_val Pointer to the old value of the atomic variable. @@ -360,8 +360,7 @@ void odp_atomic_min_u64(odp_atomic_u64_t *atom, uint64_t new_min); * * @return 0 on failure, !0 on success */ -int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val, - uint64_t new_val); +int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val, uint64_t new_val); /** * Exchange value of atomic uint64 variable @@ -414,9 +413,10 @@ void odp_atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t val); * Compare and swap atomic odp_u128_t variable * * Compares value of atomic variable to the value pointed by 'old_val'. - * If values are equal, the operation writes 'new_val' into the atomic variable - * and returns success. If they are not equal, the operation writes current - * value of atomic variable into 'old_val' and returns failure. + * If the values are equal, the operation writes 'new_val' into the atomic variable + * and returns success. The operation returns failure only when the values are + * not equal (strong CAS operation). The current value of atomic variable is written + * into 'old_val' on failure. * * @param atom Pointer to atomic variable * @param[in,out] old_val Pointer to the old value of the atomic variable. @@ -425,8 +425,7 @@ void odp_atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t val); * * @return 0 on failure, !0 on success */ -int odp_atomic_cas_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, - odp_u128_t new_val); +int odp_atomic_cas_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val); /* * 32-bit operations in non-RELAXED memory ordering -- cgit v1.2.3 From 573502fd19aac283156efe3a330b7f07289d99d0 Mon Sep 17 00:00:00 2001 From: Anoob Joseph Date: Tue, 10 Nov 2020 12:01:15 +0000 Subject: api: ipsec: allow IPsec post-processing in odp_ipsec_result API Allow implementations to perform additional post-processing in odp_ipsec_result API in ASYNC and inline cases. If application consumes packet data without checking IPsec result status, the behavior is undefined. Signed-off-by: Anoob Joseph Reviewed-by: Janne Peltonen Reviewed-by: Petri Savolainen --- include/odp/api/spec/ipsec.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h index 156d66019..0a45dd95d 100644 --- a/include/odp/api/spec/ipsec.h +++ b/include/odp/api/spec/ipsec.h @@ -63,6 +63,9 @@ typedef enum odp_ipsec_op_mode_t { * Packet input/output is connected directly to IPSEC inbound/outbound * processing. Application uses asynchronous or inline IPSEC * operations. + * + * Inline processed inbound packets are delivered to the application + * in the same way as packets processed by odp_ipsec_in_enq(). */ ODP_IPSEC_OP_MODE_INLINE, @@ -1575,6 +1578,12 @@ int odp_ipsec_out(const odp_packet_t pkt_in[], int num_in, * may be processed simultaneously in both modes (initiated by this function * and inline operation). * + * Post-processing may be required after the reception of an IPsec packet + * event to complete IPsec processing for the packet. The post-processing + * happens in the odp_ipsec_result() function that must be called at least + * once before packet data or metadata (other than packet type and subtype) + * may be accessed. + * * @param pkt Packets to be processed * @param num Number of packets to be processed * @param param Inbound operation parameters @@ -1611,6 +1620,12 @@ int odp_ipsec_in_enq(const odp_packet_t pkt[], int num, * The function may be used also in inline processing mode, e.g. for IPSEC * packets for which inline processing is not possible. * + * Post-processing may be required after the reception of an IPsec packet + * event to complete IPsec processing for the packet. The post-processing + * happens in the odp_ipsec_result() function that must be called at least + * once before packet data or metadata (other than packet type and subtype) + * may be accessed. + * * @param pkt Packets to be processed * @param num Number of packets to be processed * @param param Outbound operation parameters -- cgit v1.2.3 From db0f886dc83f548cbb8dd505728cb5f5fe1dec7e Mon Sep 17 00:00:00 2001 From: Sachin Yaligar Date: Tue, 15 Sep 2020 12:38:17 +0000 Subject: api: ipsec: add SA update test API With IPSEC implementations, the protocol specific fields like sequence number is not exposed to the application. But for debugging as well as for validation, finer control of such fields would be required. The odp_ipsec_test_sa_update(), API would allow access to such fields which are not expected to be exposed in the data path. Signed-off-by: Sachin Yaligar Signed-off-by: Aakash Sasidharan Reviewed-by: Janne Peltonen Reviewed-by: Petri Savolainen --- include/odp/api/spec/ipsec.h | 97 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h index 0a45dd95d..298fb411a 100644 --- a/include/odp/api/spec/ipsec.h +++ b/include/odp/api/spec/ipsec.h @@ -74,6 +74,46 @@ typedef enum odp_ipsec_op_mode_t { } odp_ipsec_op_mode_t; +/** + * IPSEC TEST SA operation + */ +typedef enum odp_ipsec_test_sa_operation_t { + /** Update next sequence number + * + * The seq_num parameter is an outbound SA specific parameter. + * Invoking the odp_ipsec_test_sa_update() API to update this + * field on an inbound SA will cause the API to return failure. + */ + ODP_IPSEC_TEST_SA_UPDATE_SEQ_NUM = 0, + + /** Update highest authenticated sequence number + * + * The antireplay_window_top parameter is inbound SA specific. + * Invoking the odp_ipsec_test_sa_update() API to update this + * field on an outbound SA will cause the API to return failure. + */ + ODP_IPSEC_TEST_SA_UPDATE_ANTIREPLAY_WINDOW_TOP + +} odp_ipsec_test_sa_operation_t; + +/** + * IPSEC TEST SA parameter + */ +typedef union odp_ipsec_test_sa_param_t { + /** Next sequence number + * + * @see ODP_IPSEC_TEST_SA_UPDATE_SEQ_NUM + */ + uint64_t seq_num; + + /** Highest authenticated sequence number + * + * @see ODP_IPSEC_TEST_SA_UPDATE_ANTIREPLAY_WINDOW_TOP + */ + uint64_t antireplay_window_top; + +} odp_ipsec_test_sa_param_t; + /** * Configuration options for IPSEC inbound processing */ @@ -195,6 +235,28 @@ typedef struct odp_ipsec_outbound_config_t { } odp_ipsec_outbound_config_t; +/** + * IPSEC TEST capability + */ +typedef struct odp_ipsec_test_capability_t { + /** Parameters supported for sa_update */ + struct { + /** Next sequence number value + * + * @see ODP_IPSEC_TEST_SA_UPDATE_SEQ_NUM + */ + odp_bool_t seq_num; + + /** Highest authenticated sequence number + * + * @see ODP_IPSEC_TEST_SA_UPDATE_ANTIREPLAY_WINDOW_TOP + */ + odp_bool_t antireplay_window_top; + + } sa_operations; + +} odp_ipsec_test_capability_t; + /** * IPSEC capability */ @@ -276,6 +338,11 @@ typedef struct odp_ipsec_capability_t { */ odp_support_t inline_ipsec_tm; + /** IPSEC TEST capabilities + * + * @see odp_ipsec_test_sa_update() + */ + odp_ipsec_test_capability_t test; } odp_ipsec_capability_t; /** @@ -1730,6 +1797,36 @@ int odp_ipsec_result(odp_ipsec_packet_result_t *result, odp_packet_t packet); */ int odp_ipsec_status(odp_ipsec_status_t *status, odp_event_t event); +/** + * IPSEC test API for modifying internal state of an SA. + * + * This function is not meant to be used by normal applications but by special + * test applications that test or debug the operation of the underlying ODP + * implementation. Calling this function may degrade the performance of the + * calling thread, other threads or the IPSEC implementation in general. + * + * Calling this function for an SA at the same time when the SA is used for + * processing traffic or when the SA is being modified through other parts + * of IPSEC API may result in undefined behaviour. + * + * SA state update through this function may not be supported by all ODP + * implementations, ODP instances or SA instances or at every moment. This + * function may return failure for unspecified reasons even when the capability + * call indicated support for updating a particular parameter and previous + * similar calls succeeded. + * + * @param sa IPSEC SA to be updated + * @param op Specifies operation to be performed + * @param param Pointer to IPSEC TEST SA param structure to be + * used for the operation + * + * @return 0 On success + * @retval <0 On failure + */ +int odp_ipsec_test_sa_update(odp_ipsec_sa_t sa, + odp_ipsec_test_sa_operation_t op, + const odp_ipsec_test_sa_param_t *param); + /** * Update MTU for outbound IP fragmentation * -- cgit v1.2.3 From 8f02ed72529d22724c1651e9d5203f8885872b93 Mon Sep 17 00:00:00 2001 From: Sachin Yaligar Date: Tue, 15 Sep 2020 12:12:46 +0000 Subject: linux-gen: ipsec: add odp_ipsec_test_sa_update Implement odp_ipsec_test_sa_update() API to allow the application to modify IPSEC SA parameters. Signed-off-by: Sachin Yaligar Signed-off-by: Aakash Sasidharan Reviewed-by: Janne Peltonen --- platform/linux-generic/odp_ipsec.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/platform/linux-generic/odp_ipsec.c b/platform/linux-generic/odp_ipsec.c index 57a0a167d..f8746f812 100644 --- a/platform/linux-generic/odp_ipsec.c +++ b/platform/linux-generic/odp_ipsec.c @@ -136,6 +136,7 @@ int odp_ipsec_capability(odp_ipsec_capability_t *capa) capa->max_queues = queue_capa.max_queues; capa->inline_ipsec_tm = ODP_SUPPORT_NO; + capa->test.sa_operations.seq_num = 1; return 0; } @@ -2040,6 +2041,26 @@ err: return in_pkt; } +int odp_ipsec_test_sa_update(odp_ipsec_sa_t sa, + odp_ipsec_test_sa_operation_t sa_op, + const odp_ipsec_test_sa_param_t *sa_param) +{ + ipsec_sa_t *ipsec_sa; + + ipsec_sa = _odp_ipsec_sa_entry_from_hdl(sa); + ODP_ASSERT(NULL != ipsec_sa); + + switch (sa_op) { + case ODP_IPSEC_TEST_SA_UPDATE_SEQ_NUM: + odp_atomic_store_u64(&ipsec_sa->hot.out.seq, sa_param->seq_num); + break; + default: + return -1; + } + + return 0; +} + int odp_ipsec_result(odp_ipsec_packet_result_t *result, odp_packet_t packet) { odp_ipsec_packet_result_t *res; -- cgit v1.2.3 From 04a90bcbe3082a4feaf660a14c38ea5ab2967590 Mon Sep 17 00:00:00 2001 From: Sachin Yaligar Date: Fri, 30 Oct 2020 12:42:42 +0000 Subject: validation: ipsec: add test for SA update Add outbound test to verify odp_ipsec_test_sa_update() API for seq_num parameter. Signed-off-by: Sachin Yaligar Signed-off-by: Aakash Sasidharan Reviewed-by: Janne Peltonen --- test/validation/api/ipsec/ipsec.c | 57 ++++++++++++++++++++++++++++++ test/validation/api/ipsec/ipsec.h | 4 +++ test/validation/api/ipsec/ipsec_test_out.c | 30 ++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/test/validation/api/ipsec/ipsec.c b/test/validation/api/ipsec/ipsec.c index 43322e36c..1458e9953 100644 --- a/test/validation/api/ipsec/ipsec.c +++ b/test/validation/api/ipsec/ipsec.c @@ -261,6 +261,18 @@ int ipsec_check_esp_chacha20_poly1305(void) ODP_AUTH_ALG_CHACHA20_POLY1305, 0); } +int ipsec_check_test_sa_update_seq_num(void) +{ + odp_ipsec_capability_t capa; + + odp_ipsec_capability(&capa); + + if (!capa.test.sa_operations.seq_num) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + void ipsec_sa_param_fill(odp_ipsec_sa_param_t *param, odp_bool_t in, odp_bool_t ah, @@ -734,6 +746,48 @@ static int ipsec_send_out_one(const ipsec_test_part *part, return num_out; } +int ipsec_test_sa_update_seq_num(odp_ipsec_sa_t sa, uint32_t seq_num) +{ + odp_ipsec_test_sa_operation_t sa_op; + odp_ipsec_test_sa_param_t sa_param; + + sa_op = ODP_IPSEC_TEST_SA_UPDATE_SEQ_NUM; + sa_param.seq_num = seq_num; + + return odp_ipsec_test_sa_update(sa, sa_op, &sa_param); +} + +static void ipsec_pkt_seq_num_check(odp_packet_t pkt, uint32_t seq_num) +{ + uint32_t l3_off = odp_packet_l3_offset(pkt); + uint32_t l4_off; + odph_ipv4hdr_t ip; + + CU_ASSERT_NOT_EQUAL_FATAL(ODP_PACKET_OFFSET_INVALID, l3_off); + CU_ASSERT_EQUAL_FATAL(0, odp_packet_copy_to_mem(pkt, l3_off, sizeof(ip), + &ip)); + + if (ODPH_IPV4HDR_VER(ip.ver_ihl) == ODPH_IPV4) { + l4_off = l3_off + (ODPH_IPV4HDR_IHL(ip.ver_ihl) * 4); + + if (ip.proto == ODPH_IPPROTO_ESP) { + odph_esphdr_t esp; + + odp_packet_copy_to_mem(pkt, l4_off, sizeof(esp), &esp); + CU_ASSERT_EQUAL(odp_be_to_cpu_32(esp.seq_no), seq_num); + } else if (ip.proto == ODPH_IPPROTO_AH) { + odph_ahhdr_t ah; + + odp_packet_copy_to_mem(pkt, l4_off, sizeof(ah), &ah); + CU_ASSERT_EQUAL(odp_be_to_cpu_32(ah.seq_no), seq_num); + } else { + CU_FAIL("Unexpected IP Proto"); + } + } else { + CU_FAIL("Unexpected IP Version"); + } +} + static void ipsec_pkt_proto_err_set(odp_packet_t pkt) { uint32_t l3_off = odp_packet_l3_offset(pkt); @@ -898,6 +952,9 @@ void ipsec_check_out_in_one(const ipsec_test_part *part, CU_ASSERT_FATAL(odp_packet_len(pkto[i]) <= sizeof(pkt_in.data)); + if (part->flags.test_sa_seq_num) + ipsec_pkt_seq_num_check(pkto[i], part->out[i].seq_num); + if (part->flags.stats == IPSEC_TEST_STATS_PROTO_ERR) ipsec_pkt_proto_err_set(pkto[i]); diff --git a/test/validation/api/ipsec/ipsec.h b/test/validation/api/ipsec/ipsec.h index a9213b420..3bbcb7b64 100644 --- a/test/validation/api/ipsec/ipsec.h +++ b/test/validation/api/ipsec/ipsec.h @@ -59,6 +59,7 @@ typedef struct { odp_bool_t lookup; odp_bool_t ah; odp_bool_t inline_hdr_in_packet; + odp_bool_t test_sa_seq_num; enum ipsec_test_stats stats; } ipsec_test_flags; @@ -73,6 +74,7 @@ typedef struct { const ipsec_test_packet *pkt_res; odp_proto_l3_type_t l3_type; odp_proto_l4_type_t l4_type; + uint32_t seq_num; } out[1]; struct { odp_ipsec_op_status_t status; @@ -101,6 +103,7 @@ void ipsec_check_out_one(const ipsec_test_part *part, odp_ipsec_sa_t sa); void ipsec_check_out_in_one(const ipsec_test_part *part, odp_ipsec_sa_t sa, odp_ipsec_sa_t sa_in); +int ipsec_test_sa_update_seq_num(odp_ipsec_sa_t sa, uint32_t seq_num); int ipsec_check(odp_bool_t ah, odp_cipher_alg_t cipher, @@ -128,5 +131,6 @@ int ipsec_check_esp_null_aes_gmac_128(void); int ipsec_check_esp_null_aes_gmac_192(void); int ipsec_check_esp_null_aes_gmac_256(void); int ipsec_check_esp_chacha20_poly1305(void); +int ipsec_check_test_sa_update_seq_num(void); #endif diff --git a/test/validation/api/ipsec/ipsec_test_out.c b/test/validation/api/ipsec/ipsec_test_out.c index 7035f9512..8cc7bb0b7 100644 --- a/test/validation/api/ipsec/ipsec_test_out.c +++ b/test/validation/api/ipsec/ipsec_test_out.c @@ -460,6 +460,21 @@ static void test_out_in_common(ipsec_test_flags *flags, test_ipsec_stats_zero_assert(&stats); } + if (flags->test_sa_seq_num) { + int rc; + + test.out[0].seq_num = 0x1235; + rc = ipsec_test_sa_update_seq_num(sa_out, test.out[0].seq_num); + + /* Skip further checks related to this specific test if the + * SA update call was not successful. + */ + if (rc < 0) { + printf("\t >> skipped"); + test.flags.test_sa_seq_num = false; + } + } + ipsec_check_out_in_one(&test, sa_out, sa_in); if (flags->stats == IPSEC_TEST_STATS_SUCCESS) { @@ -1392,6 +1407,19 @@ static void test_sa_info(void) ipsec_sa_destroy(sa_in); } +static void test_test_sa_update_seq_num(void) +{ + ipsec_test_flags flags; + + memset(&flags, 0, sizeof(flags)); + flags.display_algo = true; + flags.test_sa_seq_num = true; + + test_esp_out_in_all(&flags); + + printf("\n "); +} + static void ipsec_test_capability(void) { odp_ipsec_capability_t capa; @@ -1472,6 +1500,8 @@ odp_testinfo_t ipsec_out_suite[] = { ipsec_check_esp_null_sha256), ODP_TEST_INFO_CONDITIONAL(test_sa_info, ipsec_check_esp_aes_cbc_128_sha1), + ODP_TEST_INFO_CONDITIONAL(test_test_sa_update_seq_num, + ipsec_check_test_sa_update_seq_num), ODP_TEST_INFO(test_esp_out_in_all_basic), ODP_TEST_INFO_CONDITIONAL(test_esp_out_in_all_hdr_in_packet, is_out_mode_inline), -- cgit v1.2.3 From 2fab1e161ece29f32e46c72c846d5ad3e4d84308 Mon Sep 17 00:00:00 2001 From: Janne Peltonen Date: Wed, 17 Feb 2021 14:41:40 +0200 Subject: api: ipsec: let sa_info() return non-exact copy of SA parameters Do not require that the SA parameters returned by odp_ipsec_sa_info() are an exact copy of the parameters used at SA creation time as that would require implementations to remember the content of also those fields that were ignored (e.g. tunnel parameters for transport mode SA). Signed-off-by: Janne Peltonen Reviewed-by: Petri Savolainen Reviewed-by: Anoob Joseph --- include/odp/api/spec/ipsec.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h index 298fb411a..cb08465c8 100644 --- a/include/odp/api/spec/ipsec.h +++ b/include/odp/api/spec/ipsec.h @@ -884,7 +884,14 @@ typedef struct odp_ipsec_stats_t { * IPSEC SA information */ typedef struct odp_ipsec_sa_info_t { - /** Copy of IPSEC Security Association (SA) parameters */ + /** IPsec SA parameters + * + * This is not necessarily an exact copy of the actual parameter + * structure used in SA creation. The fields that were relevant + * for the SA in the creation phase will have the same values, + * but other fields, such as tunnel parameters for a transport + * mode SA, will have undefined values. + */ odp_ipsec_sa_param_t param; /** IPSEC SA direction dependent parameters */ -- cgit v1.2.3 From ae5bf27af8405311fe87508989b27c614ef8c951 Mon Sep 17 00:00:00 2001 From: Janne Peltonen Date: Wed, 17 Feb 2021 14:41:45 +0200 Subject: api: ipsec: define default values for more SA parameter fields ODP applications should use odp_ipsec_sa_param_init() to initialize SA creation parameters to their default values for better backward compatibility when new fields get added in the parameter structure. Define default values for more fields of odp_ipsec_sa_param_t so that applications do not always have to explicitly initialize as many fields after the odp_ipsec_sa_param_init() call. Change a couple of the internal unions contained in odp_ipsec_sa_param_t to structures so that it is possible to define and set default values in the contained structures. This makes it also possible to add fields in those structures in a backward compatible manner in future API changes. Signed-off-by: Janne Peltonen Reviewed-by: Petri Savolainen Reviewed-by: Anoob Joseph --- include/odp/api/spec/ipsec.h | 46 +++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/include/odp/api/spec/ipsec.h b/include/odp/api/spec/ipsec.h index cb08465c8..d1856432b 100644 --- a/include/odp/api/spec/ipsec.h +++ b/include/odp/api/spec/ipsec.h @@ -522,13 +522,13 @@ typedef struct odp_ipsec_ipv4_param_t { /** IPv4 destination address (NETWORK ENDIAN) */ void *dst_addr; - /** IPv4 Differentiated Services Code Point */ + /** IPv4 Differentiated Services Code Point. The default value is 0. */ uint8_t dscp; - /** IPv4 Don't Fragment bit */ + /** IPv4 Don't Fragment bit. The default value is 0. */ uint8_t df; - /** IPv4 Time To Live */ + /** IPv4 Time To Live. The default value is 255. */ uint8_t ttl; } odp_ipsec_ipv4_param_t; @@ -541,13 +541,13 @@ typedef struct odp_ipsec_ipv6_param_t { /** IPv6 destination address (NETWORK ENDIAN) */ void *dst_addr; - /** IPv6 flow label */ + /** IPv6 flow label. The default value is 0. */ uint32_t flabel; - /** IPv6 Differentiated Services Code Point */ + /** IPv6 Differentiated Services Code Point. The default value is 0. */ uint8_t dscp; - /** IPv6 hop limit */ + /** IPv6 hop limit. The default value is 255. */ uint8_t hlimit; } odp_ipsec_ipv6_param_t; @@ -561,11 +561,11 @@ typedef struct odp_ipsec_ipv6_param_t { * pointers and copied byte-by-byte from memory to the packet. */ typedef struct odp_ipsec_tunnel_param_t { - /** Tunnel type: IPv4 or IPv6 */ + /** Tunnel type: IPv4 or IPv6. The default is IPv4. */ odp_ipsec_tunnel_type_t type; - /** Variant mappings for tunnel parameters */ - union { + /** Tunnel type specific parameters */ + struct { /** IPv4 header parameters */ odp_ipsec_ipv4_param_t ipv4; @@ -581,7 +581,7 @@ typedef struct odp_ipsec_sa_opt_t { /** Extended Sequence Numbers (ESN) * * * 1: Use extended (64 bit) sequence numbers - * * 0: Use normal sequence numbers + * * 0: Use normal sequence numbers (the default value) */ uint32_t esn : 1; @@ -589,7 +589,7 @@ typedef struct odp_ipsec_sa_opt_t { * * * 1: Do UDP encapsulation/decapsulation so that IPSEC packets can * traverse through NAT boxes. - * * 0: No UDP encapsulation + * * 0: No UDP encapsulation (the default value) */ uint32_t udp_encap : 1; @@ -599,7 +599,7 @@ typedef struct odp_ipsec_sa_opt_t { * the outer IP header in encapsulation, and vice versa in * decapsulation. * * 0: Use values from odp_ipsec_tunnel_param_t in encapsulation and - * do not change DSCP field in decapsulation. + * do not change DSCP field in decapsulation (the default value). */ uint32_t copy_dscp : 1; @@ -607,7 +607,7 @@ typedef struct odp_ipsec_sa_opt_t { * * * 1: Copy IPv6 flow label from inner IPv6 header to the * outer IPv6 header. - * * 0: Use value from odp_ipsec_tunnel_param_t + * * 0: Use value from odp_ipsec_tunnel_param_t (the default value) */ uint32_t copy_flabel : 1; @@ -615,7 +615,7 @@ typedef struct odp_ipsec_sa_opt_t { * * * 1: Copy the DF bit from the inner IPv4 header to the outer * IPv4 header. - * * 0: Use value from odp_ipsec_tunnel_param_t + * * 0: Use value from odp_ipsec_tunnel_param_t (the default value) */ uint32_t copy_df : 1; @@ -624,7 +624,7 @@ typedef struct odp_ipsec_sa_opt_t { * * 1: In tunnel mode, decrement inner packet IPv4 TTL or * IPv6 Hop Limit after tunnel decapsulation, or before tunnel * encapsulation. - * * 0: Inner packet is not modified. + * * 0: Inner packet is not modified (the default value) */ uint32_t dec_ttl : 1; @@ -639,6 +639,8 @@ typedef struct odp_ipsec_sa_opt_t { * lifetime expiration is reported: only once, first N or all packets following * the limit crossing. Any number of limits may be used simultaneously. * Use zero when there is no limit. + * + * The default value is zero (i.e. no limit) for all the limits. */ typedef struct odp_ipsec_lifetime_t { /** Soft expiry limits for the session */ @@ -739,7 +741,7 @@ typedef struct odp_ipsec_sa_param_t { /** IPSEC SA direction: inbound or outbound */ odp_ipsec_dir_t dir; - /** IPSEC protocol: ESP or AH */ + /** IPSEC protocol: ESP or AH. The default value is ODP_IPSEC_ESP. */ odp_ipsec_protocol_t proto; /** IPSEC protocol mode: transport or tunnel */ @@ -782,10 +784,12 @@ typedef struct odp_ipsec_sa_param_t { uint32_t context_len; /** IPSEC SA direction dependent parameters */ - union { + struct { /** Inbound specific parameters */ struct { - /** SA lookup mode */ + /** SA lookup mode + * The default value is ODP_IPSEC_LOOKUP_DISABLED. + */ odp_ipsec_lookup_mode_t lookup_mode; /** Additional SA lookup parameters. Values are @@ -802,7 +806,7 @@ typedef struct odp_ipsec_sa_param_t { } lookup_param; /** Minimum anti-replay window size. Use 0 to disable - * anti-replay service. + * anti-replay service. The default value is 0. */ uint32_t antireplay_ws; @@ -835,7 +839,9 @@ typedef struct odp_ipsec_sa_param_t { /** Parameters for tunnel mode */ odp_ipsec_tunnel_param_t tunnel; - /** Fragmentation mode */ + /** Fragmentation mode + * The default value is ODP_IPSEC_FRAG_DISABLED. + */ odp_ipsec_frag_mode_t frag_mode; /** MTU for outbound IP fragmentation offload -- cgit v1.2.3 From c8a9f0d90345ae130a5ea8704e47b67cc20775cf Mon Sep 17 00:00:00 2001 From: Janne Peltonen Date: Wed, 17 Feb 2021 14:41:50 +0200 Subject: linux-gen: ipsec: set ttl and hop limit defaults according to the API Implement the recent API change that defines 255 as the default value of ttl and hop limit in odp_ipsec_sa_param_init(). Signed-off-by: Janne Peltonen Reviewed-by: Petri Savolainen Reviewed-by: Anoob Joseph --- platform/linux-generic/odp_ipsec_sad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/linux-generic/odp_ipsec_sad.c b/platform/linux-generic/odp_ipsec_sad.c index a4a349077..7cae32703 100644 --- a/platform/linux-generic/odp_ipsec_sad.c +++ b/platform/linux-generic/odp_ipsec_sad.c @@ -318,6 +318,8 @@ void odp_ipsec_sa_param_init(odp_ipsec_sa_param_t *param) { memset(param, 0, sizeof(odp_ipsec_sa_param_t)); param->dest_queue = ODP_QUEUE_INVALID; + param->outbound.tunnel.ipv4.ttl = 255; + param->outbound.tunnel.ipv6.hlimit = 255; } /* Return IV length required for the cipher for IPsec use */ -- cgit v1.2.3 From de70581b0d8781837792c525a27441224447e047 Mon Sep 17 00:00:00 2001 From: Janne Peltonen Date: Wed, 17 Feb 2021 14:41:55 +0200 Subject: validation: ipsec: test default values set by init functions Test that odp_ipsec_config_init() and odp_ipsec_sa_param_init() initialize the structures with the default values specified in the API. Signed-off-by: Janne Peltonen Reviewed-by: Petri Savolainen Reviewed-by: Anoob Joseph --- test/validation/api/ipsec/ipsec_test_out.c | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/validation/api/ipsec/ipsec_test_out.c b/test/validation/api/ipsec/ipsec_test_out.c index 8cc7bb0b7..6f285d59a 100644 --- a/test/validation/api/ipsec/ipsec_test_out.c +++ b/test/validation/api/ipsec/ipsec_test_out.c @@ -1427,6 +1427,53 @@ static void ipsec_test_capability(void) CU_ASSERT(odp_ipsec_capability(&capa) == 0); } +static void ipsec_test_default_values(void) +{ + odp_ipsec_config_t config; + odp_ipsec_sa_param_t sa_param; + + memset(&config, 0x55, sizeof(config)); + memset(&sa_param, 0x55, sizeof(sa_param)); + + odp_ipsec_config_init(&config); + CU_ASSERT(config.inbound.lookup.min_spi == 0); + CU_ASSERT(config.inbound.lookup.max_spi == UINT32_MAX); + CU_ASSERT(config.inbound.lookup.spi_overlap == 0); + CU_ASSERT(config.inbound.retain_outer == ODP_PROTO_LAYER_NONE); + CU_ASSERT(config.inbound.parse_level == ODP_PROTO_LAYER_NONE); + CU_ASSERT(config.inbound.chksums.all_chksum == 0); + CU_ASSERT(config.outbound.all_chksum == 0); + CU_ASSERT(!config.stats_en); + + odp_ipsec_sa_param_init(&sa_param); + CU_ASSERT(sa_param.proto == ODP_IPSEC_ESP); + CU_ASSERT(sa_param.crypto.cipher_alg == ODP_CIPHER_ALG_NULL); + CU_ASSERT(sa_param.crypto.auth_alg == ODP_AUTH_ALG_NULL); + CU_ASSERT(sa_param.opt.esn == 0); + CU_ASSERT(sa_param.opt.udp_encap == 0); + CU_ASSERT(sa_param.opt.copy_dscp == 0); + CU_ASSERT(sa_param.opt.copy_flabel == 0); + CU_ASSERT(sa_param.opt.copy_df == 0); + CU_ASSERT(sa_param.opt.dec_ttl == 0); + CU_ASSERT(sa_param.lifetime.soft_limit.bytes == 0); + CU_ASSERT(sa_param.lifetime.soft_limit.packets == 0); + CU_ASSERT(sa_param.lifetime.hard_limit.bytes == 0); + CU_ASSERT(sa_param.lifetime.hard_limit.packets == 0); + CU_ASSERT(sa_param.context == NULL); + CU_ASSERT(sa_param.context_len == 0); + CU_ASSERT(sa_param.inbound.lookup_mode == ODP_IPSEC_LOOKUP_DISABLED); + CU_ASSERT(sa_param.inbound.antireplay_ws == 0); + CU_ASSERT(sa_param.inbound.pipeline == ODP_IPSEC_PIPELINE_NONE); + CU_ASSERT(sa_param.outbound.tunnel.type == ODP_IPSEC_TUNNEL_IPV4); + CU_ASSERT(sa_param.outbound.tunnel.ipv4.dscp == 0); + CU_ASSERT(sa_param.outbound.tunnel.ipv4.df == 0); + CU_ASSERT(sa_param.outbound.tunnel.ipv4.ttl == 255); + CU_ASSERT(sa_param.outbound.tunnel.ipv6.flabel == 0); + CU_ASSERT(sa_param.outbound.tunnel.ipv6.dscp == 0); + CU_ASSERT(sa_param.outbound.tunnel.ipv6.hlimit == 255); + CU_ASSERT(sa_param.outbound.frag_mode == ODP_IPSEC_FRAG_DISABLED); +} + static void test_ipsec_stats(void) { ipsec_test_flags flags; @@ -1450,6 +1497,7 @@ static void test_ipsec_stats(void) odp_testinfo_t ipsec_out_suite[] = { ODP_TEST_INFO(ipsec_test_capability), + ODP_TEST_INFO(ipsec_test_default_values), ODP_TEST_INFO_CONDITIONAL(test_out_ipv4_ah_sha256, ipsec_check_ah_sha256), ODP_TEST_INFO_CONDITIONAL(test_out_ipv4_ah_sha256_tun_ipv4, -- cgit v1.2.3 From 6cab1384f6491e55a8e1dcfc8584c0558bfc25b0 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 12 Feb 2021 14:11:00 +0200 Subject: api: timer: const user context pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change user context pointer to be const when application gives it to implementation. Pointer is not const when application gets it back (odp_timeout_user_ptr()). Signed-off-by: Petri Savolainen Reviewed-by: Jerin Jacob Reviewed-by: Jere Leppänen --- include/odp/api/spec/timer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/odp/api/spec/timer.h b/include/odp/api/spec/timer.h index 22c4fbef8..1abff5160 100644 --- a/include/odp/api/spec/timer.h +++ b/include/odp/api/spec/timer.h @@ -383,8 +383,7 @@ int odp_timer_pool_info(odp_timer_pool_t timer_pool, * @return Timer handle on success * @retval ODP_TIMER_INVALID on failure and errno set. */ -odp_timer_t odp_timer_alloc(odp_timer_pool_t timer_pool, odp_queue_t queue, - void *user_ptr); +odp_timer_t odp_timer_alloc(odp_timer_pool_t timer_pool, odp_queue_t queue, const void *user_ptr); /** * Free a timer -- cgit v1.2.3 From a1a2a326ac52755891ad47b95f8c2fbcd28e94dd Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 12 Feb 2021 14:15:42 +0200 Subject: linux-gen: timer: change user pointer to const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align to API change of user pointer type. Signed-off-by: Petri Savolainen Reviewed-by: Jerin Jacob Reviewed-by: Jere Leppänen --- platform/linux-generic/include/odp_timer_internal.h | 5 ++++- platform/linux-generic/odp_timer.c | 17 +++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/platform/linux-generic/include/odp_timer_internal.h b/platform/linux-generic/include/odp_timer_internal.h index 17ebf2684..0c2a0fe4b 100644 --- a/platform/linux-generic/include/odp_timer_internal.h +++ b/platform/linux-generic/include/odp_timer_internal.h @@ -29,10 +29,13 @@ typedef struct { /* Requested expiration time */ uint64_t expiration; + /* User ptr inherited from parent timer */ - void *user_ptr; + const void *user_ptr; + /* Parent timer */ odp_timer_t timer; + } odp_timeout_hdr_t; /* A larger decrement value should be used after receiving events compared to diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index bdff3ab9b..5111c369a 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -107,7 +107,7 @@ ODP_STATIC_ASSERT(sizeof(tick_buf_t) == 16, "sizeof(tick_buf_t) == 16"); #endif typedef struct { - void *user_ptr; + const void *user_ptr; odp_queue_t queue;/* Used for free list when timer is free */ } _odp_timer_t; @@ -187,10 +187,7 @@ static __thread timer_local_t timer_local; static void itimer_init(timer_pool_t *tp); static void itimer_fini(timer_pool_t *tp); -static void timer_init(_odp_timer_t *tim, - tick_buf_t *tb, - odp_queue_t _q, - void *_up) +static void timer_init(_odp_timer_t *tim, tick_buf_t *tb, odp_queue_t _q, const void *_up) { tim->queue = _q; tim->user_ptr = _up; @@ -488,9 +485,7 @@ static void odp_timer_pool_del(timer_pool_t *tp) ODP_ABORT("Failed to free shared memory (%d)\n", rc); } -static inline odp_timer_t timer_alloc(timer_pool_t *tp, - odp_queue_t queue, - void *user_ptr) +static inline odp_timer_t timer_alloc(timer_pool_t *tp, odp_queue_t queue, const void *user_ptr) { odp_timer_t hdl; @@ -1358,9 +1353,7 @@ uint64_t odp_timer_pool_to_u64(odp_timer_pool_t tpid) return _odp_pri(tpid); } -odp_timer_t odp_timer_alloc(odp_timer_pool_t tpid, - odp_queue_t queue, - void *user_ptr) +odp_timer_t odp_timer_alloc(odp_timer_pool_t tpid, odp_queue_t queue, const void *user_ptr) { timer_pool_t *tp = timer_pool_from_hdl(tpid); @@ -1491,7 +1484,7 @@ uint64_t odp_timeout_tick(odp_timeout_t tmo) void *odp_timeout_user_ptr(odp_timeout_t tmo) { - return timeout_hdr(tmo)->user_ptr; + return (void *)(uintptr_t)timeout_hdr(tmo)->user_ptr; } odp_timeout_t odp_timeout_alloc(odp_pool_t pool) -- cgit v1.2.3 From cf8e2f825edb43985b84a4112b920141a9ac8cbe Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 11 Feb 2021 17:12:19 +0200 Subject: api: timer: add debug print functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added debug print functions for timer pool, timer and timeout. Signed-off-by: Petri Savolainen Reviewed-by: Jerin Jacob Reviewed-by: Jere Leppänen --- include/odp/api/spec/timer.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/odp/api/spec/timer.h b/include/odp/api/spec/timer.h index 1abff5160..62151e485 100644 --- a/include/odp/api/spec/timer.h +++ b/include/odp/api/spec/timer.h @@ -564,6 +564,36 @@ odp_timeout_t odp_timeout_alloc(odp_pool_t pool); */ void odp_timeout_free(odp_timeout_t tmo); +/** + * Print timer pool debug information + * + * Prints implementation specific debug information about + * the timer pool to the ODP log. + * + * @param timer_pool Timer pool handle + */ +void odp_timer_pool_print(odp_timer_pool_t timer_pool); + +/** + * Print timer debug information + * + * Prints implementation specific debug information about + * the timer to the ODP log. + * + * @param timer Timer handle + */ +void odp_timer_print(odp_timer_t timer); + +/** + * Print timeout debug information + * + * Prints implementation specific debug information about + * the timeout to the ODP log. + * + * @param tmo Timeout handle + */ +void odp_timeout_print(odp_timeout_t tmo); + /** * Get printable value for an odp_timer_pool_t * -- cgit v1.2.3 From 5e513782866833a01c886ec5ab08b5fa3645c289 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 12 Feb 2021 08:47:26 +0200 Subject: linux-gen: timer: implement debug print functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement new debug print API functions. Signed-off-by: Petri Savolainen Reviewed-by: Jerin Jacob Reviewed-by: Jere Leppänen --- platform/linux-generic/odp_timer.c | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 5111c369a..8b2ba16c2 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -1503,6 +1503,81 @@ void odp_timeout_free(odp_timeout_t tmo) odp_buffer_free(odp_buffer_from_event(ev)); } +void odp_timer_pool_print(odp_timer_pool_t timer_pool) +{ + timer_pool_t *tp; + + if (timer_pool == ODP_TIMER_POOL_INVALID) { + ODP_ERR("Bad timer pool handle\n"); + return; + } + + tp = timer_pool_from_hdl(timer_pool); + + ODP_PRINT("\nTimer pool info\n"); + ODP_PRINT("---------------\n"); + ODP_PRINT(" timer pool %p\n", tp); + ODP_PRINT(" tp index %u\n", tp->tp_idx); + ODP_PRINT(" num timers %u\n", tp->num_alloc); + ODP_PRINT(" num tp %i\n", timer_global->num_timer_pools); + ODP_PRINT(" inline timers %i\n", timer_global->use_inline_timers); + ODP_PRINT("\n"); +} + +void odp_timer_print(odp_timer_t timer) +{ + timer_pool_t *tp; + uint32_t idx; + _odp_timer_t *tim; + + if (timer == ODP_TIMER_INVALID) { + ODP_ERR("Bad timer handle\n"); + return; + } + + tp = handle_to_tp(timer); + idx = handle_to_idx(timer, tp); + tim = &tp->timers[idx]; + + ODP_PRINT("\nTimer info\n"); + ODP_PRINT("----------\n"); + ODP_PRINT(" timer pool %p\n", tp); + ODP_PRINT(" timer index %u\n", idx); + ODP_PRINT(" dest queue 0x%" PRIx64 "\n", odp_queue_to_u64(tim->queue)); + ODP_PRINT(" user ptr %p\n", tim->user_ptr); + ODP_PRINT("\n"); +} + +void odp_timeout_print(odp_timeout_t tmo) +{ + const odp_timeout_hdr_t *tmo_hdr; + odp_timer_t timer; + timer_pool_t *tp = NULL; + uint32_t idx = 0; + + if (tmo == ODP_TIMEOUT_INVALID) { + ODP_ERR("Bad timeout handle\n"); + return; + } + + tmo_hdr = timeout_hdr(tmo); + timer = tmo_hdr->timer; + + if (timer != ODP_TIMER_INVALID) { + tp = handle_to_tp(timer); + idx = handle_to_idx(timer, tp); + } + + ODP_PRINT("\nTimeout info\n"); + ODP_PRINT("------------\n"); + ODP_PRINT(" tmo handle 0x%" PRIx64 "\n", odp_timeout_to_u64(tmo)); + ODP_PRINT(" timer pool %p\n", tp); + ODP_PRINT(" timer index %u\n", idx); + ODP_PRINT(" expiration %" PRIu64 "\n", tmo_hdr->expiration); + ODP_PRINT(" user ptr %p\n", tmo_hdr->user_ptr); + ODP_PRINT("\n"); +} + int _odp_timer_init_global(const odp_init_t *params) { odp_shm_t shm; -- cgit v1.2.3 From 939fdd548e117e104c47facfbad65148d0925500 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 12 Feb 2021 15:11:32 +0200 Subject: validation: timer: test new timer debug print functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call the new timer debug print functions once in a plain and once in a scheduled queue test. Signed-off-by: Petri Savolainen Reviewed-by: Jerin Jacob Reviewed-by: Jere Leppänen --- test/validation/api/timer/timer.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test/validation/api/timer/timer.c b/test/validation/api/timer/timer.c index 8943d4d97..f2cc93cb8 100644 --- a/test/validation/api/timer/timer.c +++ b/test/validation/api/timer/timer.c @@ -534,6 +534,8 @@ static void timer_test_event_type(odp_queue_type_t queue_type, odp_time_t t1, t2; uint64_t period_ns, period_tick, duration_ns; int i, ret, num_tmo; + const char *user_ctx = "User context"; + int test_print = 0; int num = 5; odp_timer_t timer[num]; @@ -562,6 +564,7 @@ static void timer_test_event_type(odp_queue_type_t queue_type, } else if (event_type == ODP_EVENT_TIMEOUT) { pool_param.type = ODP_POOL_TIMEOUT; pool_param.tmo.num = num; + test_print = 1; } else { CU_FAIL("Bad event_type"); return; @@ -589,7 +592,8 @@ static void timer_test_event_type(odp_queue_type_t queue_type, ODPH_DBG(" max_tmo %" PRIu64 "\n", timer_param.max_tmo); ODPH_DBG(" period_ns %" PRIu64 "\n", period_ns); ODPH_DBG(" period_tick %" PRIu64 "\n", period_tick); - ODPH_DBG(" duration_ns %" PRIu64 "\n\n", duration_ns); + ODPH_DBG(" duration_ns %" PRIu64 "\n", duration_ns); + ODPH_DBG(" user_ptr %p\n\n", user_ctx); for (i = 0; i < num; i++) { if (event_type == ODP_EVENT_BUFFER) { @@ -605,7 +609,7 @@ static void timer_test_event_type(odp_queue_type_t queue_type, CU_ASSERT(ev != ODP_EVENT_INVALID); - timer[i] = odp_timer_alloc(timer_pool, queue, NULL); + timer[i] = odp_timer_alloc(timer_pool, queue, user_ctx); CU_ASSERT_FATAL(timer[i] != ODP_TIMER_INVALID); ret = odp_timer_set_rel(timer[i], (i + 1) * period_tick, &ev); @@ -620,6 +624,12 @@ static void timer_test_event_type(odp_queue_type_t queue_type, CU_ASSERT(ret == ODP_TIMER_SUCCESS); } + if (test_print) { + printf("\n"); + odp_timer_pool_print(timer_pool); + odp_timer_print(timer[0]); + } + ev = ODP_EVENT_INVALID; num_tmo = 0; t1 = odp_time_local(); @@ -642,6 +652,13 @@ static void timer_test_event_type(odp_queue_type_t queue_type, CU_ASSERT(odp_event_type(ev) == event_type); + if (test_print) { + test_print = 0; + tmo = odp_timeout_from_event(ev); + odp_timeout_print(tmo); + printf("\n"); + } + odp_event_free(ev); num_tmo++; -- cgit v1.2.3 From 399972bfd36f697d658b94471e9e030c3b82f667 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Fri, 12 Feb 2021 08:48:36 +0200 Subject: example: debug: add timer debug print option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add -t option which uses the new timer debug print functions. Signed-off-by: Petri Savolainen Reviewed-by: Jerin Jacob Reviewed-by: Jere Leppänen --- example/debug/odp_debug.c | 145 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 137 insertions(+), 8 deletions(-) diff --git a/example/debug/odp_debug.c b/example/debug/odp_debug.c index 1f2c7a8a2..6b09c89d6 100644 --- a/example/debug/odp_debug.c +++ b/example/debug/odp_debug.c @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include @@ -19,6 +21,7 @@ typedef struct test_global_t { int queue; int pktio; int ipsec; + int timer; } test_global_t; @@ -37,6 +40,7 @@ static void print_usage(void) " -q, --queue Create various types of queues and call odp_queue_print()\n" " -i, --interface Create packet IO interface (loop) and call odp_pktio_print()\n" " -I, --ipsec Call odp_ipsec_print()\n" + " -t, --timer Call timer pool, timer and timeout print functions\n" " -h, --help Display help and exit.\n\n"); } @@ -51,10 +55,11 @@ static int parse_options(int argc, char *argv[], test_global_t *global) {"queue", no_argument, NULL, 'q'}, {"interface", no_argument, NULL, 'i'}, {"ipsec", no_argument, NULL, 'I'}, + {"timer", no_argument, NULL, 't'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; - const char *shortopts = "+SspqiIh"; + const char *shortopts = "+SspqiIth"; int ret = 0; while (1) { @@ -82,6 +87,9 @@ static int parse_options(int argc, char *argv[], test_global_t *global) case 'I': global->ipsec = 1; break; + case 't': + global->timer = 1; + break; case 'h': default: print_usage(); @@ -258,12 +266,6 @@ static int queue_debug(void) return -1; } - /* Configure scheduler before creating any scheduled queues */ - if (odp_schedule_config(NULL)) { - ODPH_ERR("Schedule config failed\n"); - return -1; - } - name = "debug_sched_queue"; odp_queue_param_init(¶m); param.type = ODP_QUEUE_TYPE_SCHED; @@ -336,6 +338,121 @@ static int ipsec_debug(void) return 0; } +static int timer_debug(void) +{ + odp_pool_t pool; + odp_pool_param_t pool_param; + odp_timeout_t timeout; + odp_timer_capability_t timer_capa; + odp_timer_pool_t timer_pool; + odp_timer_pool_param_t timer_param; + odp_timer_t timer; + odp_queue_t queue; + odp_queue_param_t queue_param; + odp_event_t event; + uint64_t tick; + uint64_t max_tmo = ODP_TIME_SEC_IN_NS; + uint64_t res = 100 * ODP_TIME_MSEC_IN_NS; + + odp_pool_param_init(&pool_param); + pool_param.type = ODP_POOL_TIMEOUT; + pool_param.tmo.num = 10; + + pool = odp_pool_create("debug_timer", &pool_param); + + if (pool == ODP_POOL_INVALID) { + ODPH_ERR("Pool create failed\n"); + return -1; + } + + timeout = odp_timeout_alloc(pool); + if (timeout == ODP_TIMEOUT_INVALID) { + ODPH_ERR("Timeout alloc failed\n"); + return -1; + } + + if (odp_timer_capability(ODP_CLOCK_CPU, &timer_capa)) { + ODPH_ERR("Timer capa failed\n"); + return -1; + } + + if (timer_capa.max_tmo.max_tmo < max_tmo) + max_tmo = timer_capa.max_tmo.max_tmo; + + if (timer_capa.max_tmo.res_ns > res) + res = timer_capa.max_tmo.res_ns; + + memset(&timer_param, 0, sizeof(timer_param)); + timer_param.res_ns = res; + timer_param.min_tmo = max_tmo / 10; + timer_param.max_tmo = max_tmo; + timer_param.num_timers = 10; + timer_param.clk_src = ODP_CLOCK_CPU; + + timer_pool = odp_timer_pool_create("debug_timer", &timer_param); + + if (timer_pool == ODP_TIMER_POOL_INVALID) { + ODPH_ERR("Timer pool create failed\n"); + return -1; + } + + odp_timer_pool_start(); + + odp_queue_param_init(&queue_param); + if (timer_capa.queue_type_sched) + queue_param.type = ODP_QUEUE_TYPE_SCHED; + + queue = odp_queue_create("debug_timer", &queue_param); + if (queue == ODP_QUEUE_INVALID) { + ODPH_ERR("Queue create failed.\n"); + return -1; + } + + printf("\n"); + odp_timer_pool_print(timer_pool); + + tick = odp_timer_ns_to_tick(timer_pool, max_tmo / 2); + + timer = odp_timer_alloc(timer_pool, queue, (void *)(uintptr_t)0xdeadbeef); + + printf("\n"); + odp_timeout_print(timeout); + + event = odp_timeout_to_event(timeout); + if (odp_timer_set_rel(timer, tick, &event) != ODP_TIMER_SUCCESS) + ODPH_ERR("Timer set failed.\n"); + + printf("\n"); + odp_timer_print(timer); + + event = odp_timer_free(timer); + + if (event == ODP_EVENT_INVALID) { + ODPH_ERR("Timer free failed.\n"); + } else { + timeout = odp_timeout_from_event(event); + + printf("\n"); + odp_timeout_print(timeout); + + odp_timeout_free(timeout); + } + + odp_timer_pool_destroy(timer_pool); + + if (odp_queue_destroy(queue)) { + ODPH_ERR("Queue destroy failed\n"); + return -1; + } + + if (odp_pool_destroy(pool)) { + ODPH_ERR("Pool destroy failed\n"); + return -1; + } + + return 0; +} + int main(int argc, char *argv[]) { odp_instance_t inst; @@ -352,9 +469,10 @@ int main(int argc, char *argv[]) global->queue = 1; global->pktio = 1; global->ipsec = 1; + global->timer = 1; } else { if (parse_options(argc, argv, global)) - return -1; + exit(EXIT_FAILURE); } if (odp_init_global(&inst, NULL, NULL)) { @@ -367,6 +485,12 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + /* Configure scheduler before creating any scheduled queues */ + if (odp_schedule_config(NULL)) { + ODPH_ERR("Schedule config failed\n"); + exit(EXIT_FAILURE); + } + if (global->system) { printf("\n"); odp_sys_info_print(); @@ -400,6 +524,11 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + if (global->timer && timer_debug()) { + ODPH_ERR("Timer debug failed.\n"); + exit(EXIT_FAILURE); + } + if (odp_term_local()) { ODPH_ERR("Local term failed.\n"); exit(EXIT_FAILURE); -- cgit v1.2.3 From fca1ba3b7ba313018fa7e29581cf33c441788307 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 18 Feb 2021 11:05:15 +0200 Subject: api: queue: print debug info for all queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add odp_queue_print_all(), which prints implementation specific debug information for all queues. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen Reviewed-by: Matias Elo Reviewed-by: Jerin Jacob --- include/odp/api/spec/queue.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/odp/api/spec/queue.h b/include/odp/api/spec/queue.h index 0260a7a33..005229e35 100644 --- a/include/odp/api/spec/queue.h +++ b/include/odp/api/spec/queue.h @@ -304,6 +304,14 @@ int odp_queue_info(odp_queue_t queue, odp_queue_info_t *info); */ void odp_queue_print(odp_queue_t queue); +/** + * Print debug info about all queues + * + * Print implementation defined information about all created queues to the ODP + * log. The information is intended to be used for debugging. + */ +void odp_queue_print_all(void); + /** * @} */ -- cgit v1.2.3 From 72e450dd3de1cf8396f984fbf21e3aab373e47f8 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 18 Feb 2021 17:09:30 +0200 Subject: linux-gen: queue: implement odp_queue_print_all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented the new queue debug print function. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen Reviewed-by: Matias Elo --- .../include/odp/api/plat/queue_inline_types.h | 2 + platform/linux-generic/odp_queue_basic.c | 95 +++++++++++++++++++++- platform/linux-generic/odp_queue_if.c | 9 +- platform/linux-generic/odp_queue_scalable.c | 73 ++++++++++++++++- 4 files changed, 175 insertions(+), 4 deletions(-) diff --git a/platform/linux-generic/include/odp/api/plat/queue_inline_types.h b/platform/linux-generic/include/odp/api/plat/queue_inline_types.h index bbff4b412..e59c7f55a 100644 --- a/platform/linux-generic/include/odp/api/plat/queue_inline_types.h +++ b/platform/linux-generic/include/odp/api/plat/queue_inline_types.h @@ -51,6 +51,8 @@ typedef struct { void (*queue_param_init)(odp_queue_param_t *param); int (*queue_info)(odp_queue_t queue, odp_queue_info_t *info); void (*queue_print)(odp_queue_t queue); + void (*queue_print_all)(void); + } _odp_queue_api_fn_t; /** @endcond */ diff --git a/platform/linux-generic/odp_queue_basic.c b/platform/linux-generic/odp_queue_basic.c index 0ffad0807..2d2ed3c7f 100644 --- a/platform/linux-generic/odp_queue_basic.c +++ b/platform/linux-generic/odp_queue_basic.c @@ -767,6 +767,97 @@ static void queue_print(odp_queue_t handle) UNLOCK(queue); } +static void queue_print_all(void) +{ + uint32_t i, index, len, max_len; + const char *name; + int status; + odp_queue_type_t type; + odp_nonblocking_t blocking; + odp_queue_op_mode_t enq_mode; + odp_queue_op_mode_t deq_mode; + odp_queue_order_t order; + const char *status_str; + const char *bl_str; + char type_c, enq_c, deq_c, order_c, sync_c; + const int col_width = 24; + int prio = 0; + odp_schedule_sync_t sync = ODP_SCHED_SYNC_PARALLEL; + + ODP_PRINT("\nList of all queues\n"); + ODP_PRINT("------------------\n"); + ODP_PRINT(" idx %-*s type stat blk enq deq ord len max_len sync prio\n", col_width, "name"); + + for (i = 0; i < CONFIG_MAX_QUEUES; i++) { + queue_entry_t *queue = qentry_from_index(i); + + if (queue->s.status < QUEUE_STATUS_READY) + continue; + + LOCK(queue); + + status = queue->s.status; + index = queue->s.index; + name = queue->s.name; + type = queue->s.type; + blocking = queue->s.param.nonblocking; + enq_mode = queue->s.param.enq_mode; + deq_mode = queue->s.param.deq_mode; + order = queue->s.param.order; + + if (queue->s.queue_lf) { + len = _odp_queue_lf_length(queue->s.queue_lf); + max_len = _odp_queue_lf_max_length(); + } else if (queue->s.spsc) { + len = ring_spsc_length(&queue->s.ring_spsc); + max_len = queue->s.ring_mask + 1; + } else if (type == ODP_QUEUE_TYPE_SCHED) { + len = ring_st_length(&queue->s.ring_st); + max_len = queue->s.ring_mask + 1; + prio = queue->s.param.sched.prio; + sync = queue->s.param.sched.sync; + } else { + len = ring_mpmc_length(&queue->s.ring_mpmc); + max_len = queue->s.ring_mask + 1; + } + + UNLOCK(queue); + + if (status < QUEUE_STATUS_READY) + continue; + + status_str = (status == QUEUE_STATUS_READY) ? "R" : + ((status == QUEUE_STATUS_SCHED) ? "S" : "NS"); + + type_c = (type == ODP_QUEUE_TYPE_PLAIN) ? 'P' : 'S'; + + bl_str = (blocking == ODP_BLOCKING) ? "B" : + ((blocking == ODP_NONBLOCKING_LF) ? "LF" : "WF"); + + enq_c = (enq_mode == ODP_QUEUE_OP_MT) ? 'S' : + ((enq_mode == ODP_QUEUE_OP_MT_UNSAFE) ? 'U' : 'D'); + + deq_c = (deq_mode == ODP_QUEUE_OP_MT) ? 'S' : + ((deq_mode == ODP_QUEUE_OP_MT_UNSAFE) ? 'U' : 'D'); + + order_c = (order == ODP_QUEUE_ORDER_KEEP) ? 'K' : 'I'; + + ODP_PRINT("%4u %-*s %c %2s %2s", index, col_width, name, type_c, + status_str, bl_str); + ODP_PRINT(" %c %c %c %6u %6u", enq_c, deq_c, order_c, len, max_len); + + if (type == ODP_QUEUE_TYPE_SCHED) { + sync_c = (sync == ODP_SCHED_SYNC_PARALLEL) ? 'P' : + ((sync == ODP_SCHED_SYNC_ATOMIC) ? 'A' : 'O'); + ODP_PRINT(" %c %4i", sync_c, prio); + } + + ODP_PRINT("\n"); + } + + ODP_PRINT("\n"); +} + static inline int _sched_queue_enq_multi(odp_queue_t handle, odp_buffer_hdr_t *buf_hdr[], int num) { @@ -1137,7 +1228,9 @@ _odp_queue_api_fn_t _odp_queue_basic_api = { .queue_to_u64 = queue_to_u64, .queue_param_init = queue_param_init, .queue_info = queue_info, - .queue_print = queue_print + .queue_print = queue_print, + .queue_print_all = queue_print_all + }; /* Functions towards internal components */ diff --git a/platform/linux-generic/odp_queue_if.c b/platform/linux-generic/odp_queue_if.c index d4b1c550c..9ebd5db86 100644 --- a/platform/linux-generic/odp_queue_if.c +++ b/platform/linux-generic/odp_queue_if.c @@ -88,7 +88,7 @@ uint64_t odp_queue_to_u64(odp_queue_t hdl) void odp_queue_param_init(odp_queue_param_t *param) { - return _odp_queue_api->queue_param_init(param); + _odp_queue_api->queue_param_init(param); } int odp_queue_info(odp_queue_t queue, odp_queue_info_t *info) @@ -98,7 +98,12 @@ int odp_queue_info(odp_queue_t queue, odp_queue_info_t *info) void odp_queue_print(odp_queue_t queue) { - return _odp_queue_api->queue_print(queue); + _odp_queue_api->queue_print(queue); +} + +void odp_queue_print_all(void) +{ + _odp_queue_api->queue_print_all(); } int _odp_queue_init_global(void) diff --git a/platform/linux-generic/odp_queue_scalable.c b/platform/linux-generic/odp_queue_scalable.c index abb3a97c2..d70e174e0 100644 --- a/platform/linux-generic/odp_queue_scalable.c +++ b/platform/linux-generic/odp_queue_scalable.c @@ -1014,6 +1014,76 @@ static void queue_print(odp_queue_t handle) UNLOCK(&queue->s.lock); } +static void queue_print_all(void) +{ + uint32_t i, index; + const char *name; + int status; + odp_queue_type_t type; + odp_nonblocking_t blocking; + odp_queue_op_mode_t enq_mode; + odp_queue_op_mode_t deq_mode; + odp_queue_order_t order; + const char *bl_str; + char type_c, enq_c, deq_c, order_c, sync_c; + const int col_width = 24; + int prio = 0; + odp_schedule_sync_t sync = ODP_SCHED_SYNC_PARALLEL; + + ODP_PRINT("\nList of all queues\n"); + ODP_PRINT("------------------\n"); + ODP_PRINT(" idx %-*s type blk enq deq ord sync prio\n", col_width, "name"); + + for (i = 0; i < CONFIG_MAX_QUEUES; i++) { + queue_entry_t *queue = &queue_tbl->queue[i]; + + if (queue->s.status != QUEUE_STATUS_READY) + continue; + + LOCK(&queue->s.lock); + + status = queue->s.status; + index = queue->s.index; + name = queue->s.name; + type = queue->s.type; + blocking = queue->s.param.nonblocking; + enq_mode = queue->s.param.enq_mode; + deq_mode = queue->s.param.deq_mode; + order = queue->s.param.order; + + UNLOCK(&queue->s.lock); + + if (status != QUEUE_STATUS_READY) + continue; + + type_c = (type == ODP_QUEUE_TYPE_PLAIN) ? 'P' : 'S'; + + bl_str = (blocking == ODP_BLOCKING) ? "B" : + ((blocking == ODP_NONBLOCKING_LF) ? "LF" : "WF"); + + enq_c = (enq_mode == ODP_QUEUE_OP_MT) ? 'S' : + ((enq_mode == ODP_QUEUE_OP_MT_UNSAFE) ? 'U' : 'D'); + + deq_c = (deq_mode == ODP_QUEUE_OP_MT) ? 'S' : + ((deq_mode == ODP_QUEUE_OP_MT_UNSAFE) ? 'U' : 'D'); + + order_c = (order == ODP_QUEUE_ORDER_KEEP) ? 'K' : 'I'; + + ODP_PRINT("%4u %-*s %c %2s", index, col_width, name, type_c, bl_str); + ODP_PRINT(" %c %c %c", enq_c, deq_c, order_c); + + if (type == ODP_QUEUE_TYPE_SCHED) { + sync_c = (sync == ODP_SCHED_SYNC_PARALLEL) ? 'P' : + ((sync == ODP_SCHED_SYNC_ATOMIC) ? 'A' : 'O'); + ODP_PRINT(" %c %4i", sync_c, prio); + } + + ODP_PRINT("\n"); + } + + ODP_PRINT("\n"); +} + static uint64_t queue_to_u64(odp_queue_t hdl) { return _odp_pri(hdl); @@ -1100,7 +1170,8 @@ _odp_queue_api_fn_t _odp_queue_scalable_api = { .queue_to_u64 = queue_to_u64, .queue_param_init = queue_param_init, .queue_info = queue_info, - .queue_print = queue_print + .queue_print = queue_print, + .queue_print_all = queue_print_all }; /* Functions towards internal components */ -- cgit v1.2.3 From f9f91d84910fbd44d11691b87e245c2158143429 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 18 Feb 2021 17:10:51 +0200 Subject: validation: queue: test odp_queue_print_all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call the new queue debug print function from validation test. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen Reviewed-by: Matias Elo --- test/validation/api/queue/queue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/validation/api/queue/queue.c b/test/validation/api/queue/queue.c index 256194f81..b5d594a9a 100644 --- a/test/validation/api/queue/queue.c +++ b/test/validation/api/queue/queue.c @@ -759,6 +759,8 @@ static void queue_test_info(void) CU_ASSERT(info.param.sched.lock_count == lock_count); odp_queue_print(q_order); + odp_queue_print_all(); + CU_ASSERT(odp_queue_destroy(q_plain) == 0); CU_ASSERT(odp_queue_destroy(q_order) == 0); } -- cgit v1.2.3 From e23298f601467c58544f26d88f9b32d2db0c6112 Mon Sep 17 00:00:00 2001 From: Petri Savolainen Date: Thu, 18 Feb 2021 17:12:00 +0200 Subject: example: debug: use odp_queue_print_all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call the new queue debug print function. Signed-off-by: Petri Savolainen Reviewed-by: Jere Leppänen Reviewed-by: Matias Elo --- example/debug/odp_debug.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/debug/odp_debug.c b/example/debug/odp_debug.c index 6b09c89d6..48591134a 100644 --- a/example/debug/odp_debug.c +++ b/example/debug/odp_debug.c @@ -258,6 +258,9 @@ static int queue_debug(void) return -1; } + printf("\n"); + odp_queue_print_all(); + printf("\n"); odp_queue_print(queue); -- cgit v1.2.3 From 4ea350231d652bedf2cf42e395e1be5e21f41aba Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Tue, 23 Feb 2021 16:52:42 +0200 Subject: api: increment ODP API version to 1.27.0 Increment API version number to reflect the following changes: Backward-incompatible: - IPsec post-processing happens in the odp_ipsec_result() function that must be called at least once before packet data or metadata may be accessed. Backward-compatible: - New 128-bit atomic operations: init, store, load, and CAS - Clarify that atomic CAS operations are strong type - New odp_ipsec_test_sa_update() function for SA testing - odp_ipsec_sa_info() may return non-exact copy of SA parameters - Specify default values for more IPsec SA parameter fields - Changed odp_timer_alloc() user context pointer argument to const - New odp_timer_pool_print() function for printing timer pool debug information - New odp_timer_print() function for printing timer debug information - New odp_timeout_print() function for printing timeout debug information - New odp_queue_print_all() function for printing debug information about all queues Signed-off-by: Matias Elo Reviewed-by: Petri Savolainen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 75ff1d235..574f2ef24 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.5]) # ODP API version ########################################################################## m4_define([odpapi_generation_version], [1]) -m4_define([odpapi_major_version], [26]) +m4_define([odpapi_major_version], [27]) m4_define([odpapi_minor_version], [0]) m4_define([odpapi_point_version], [0]) m4_define([odpapi_version], -- cgit v1.2.3 From 374414dbf838ca362cabd4d67f24478f45d36ff4 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Tue, 20 Apr 2021 12:14:05 +0300 Subject: Port 596cec45d "linux-gen: introduce _ODP_UNALIGNED macro" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am index 4f6585c14..5dc41e4b0 100644 --- a/platform/linux-dpdk/Makefile.am +++ b/platform/linux-dpdk/Makefile.am @@ -319,6 +319,7 @@ if !ODP_ABI_COMPAT odpapiabiarchinclude_HEADERS += arch/x86/odp/api/abi/cpu.h endif noinst_HEADERS += arch/x86/cpu_flags.h \ + arch/x86/odp_cpu.h \ arch/default/odp_cpu.h \ arch/default/odp_cpu_idling.h endif -- cgit v1.2.3 From bbbdf24aedc3f05b776cba2aaaedcd9c2f0dcbd0 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Tue, 20 Apr 2021 12:16:42 +0300 Subject: Port 670970836 "linux-gen: improve software checksum implementation" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am index 5dc41e4b0..bb44c8661 100644 --- a/platform/linux-dpdk/Makefile.am +++ b/platform/linux-dpdk/Makefile.am @@ -92,8 +92,9 @@ endif noinst_HEADERS = \ ${top_srcdir}/platform/linux-generic/include/odp_align_internal.h \ ${top_srcdir}/platform/linux-generic/include/odp_atomic_internal.h \ - include/odp_buffer_internal.h \ ${top_srcdir}/platform/linux-generic/include/odp_bitset.h \ + include/odp_buffer_internal.h \ + ${top_srcdir}/platform/linux-generic/include/odp_chksum_internal.h \ ${top_srcdir}/platform/linux-generic/include/odp_classification_internal.h \ include/odp_config_internal.h \ ${top_srcdir}/platform/linux-generic/include/odp_debug_internal.h \ -- cgit v1.2.3 From df9f52a7b4f4c5fcd1812570f8753b8e2f60ae9f Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 21 Apr 2021 08:40:17 +0300 Subject: Port 3bedbf066 "linux-gen: packet: use new software checksum functions" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/odp_packet.c | 211 ++++++++++++++------------------------- 1 file changed, 75 insertions(+), 136 deletions(-) diff --git a/platform/linux-dpdk/odp_packet.c b/platform/linux-dpdk/odp_packet.c index 35c81edf4..e65a08d0e 100644 --- a/platform/linux-dpdk/odp_packet.c +++ b/platform/linux-dpdk/odp_packet.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1224,86 +1225,25 @@ int _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt) return dst_size < src_size; } -/* Simple implementation of ones complement sum. - * Based on RFC1071 and its errata. - */ -typedef union { - uint16_t w; - uint8_t b[2]; -} swap_buf_t; - -static uint32_t segment_sum16_32(const uint8_t *p, - uint32_t len, - uint32_t offset) - -{ - uint32_t sum = 0; - - /* Include second part of 16-bit short word split between segments */ - if (len > 0 && (offset % 2)) { - swap_buf_t sw; - - sw.b[0] = 0; - sw.b[1] = *p++; - sum = sw.w; - len--; - } - - /* - * If pointer is 16-bit aligned, we can do fast path calculation. - * If it is not, we sum hi and lo bytes separately and then sum them. - */ - if ((uintptr_t)p % 2) { - uint32_t sum1 = 0, sum2 = 0; - - while (len > 1) { - sum1 += *p++; - sum2 += *p++; - len -= 2; - } -#if (ODP_BYTE_ORDER == ODP_BIG_ENDIAN) - sum += sum2 + (sum1 << 8); -#else - sum += sum1 + (sum2 << 8); -#endif - } else { - while (len > 1) { - sum += *(const uint16_t *)(uintptr_t)p; - p += 2; - len -= 2; - } - } - - /* Add left-over byte, if any */ - if (len > 0) { - swap_buf_t sw; - - sw.b[0] = *p; - sw.b[1] = 0; - sum += sw.w; - } - - return sum; -} - -static uint32_t packet_sum16_32(odp_packet_hdr_t *pkt_hdr, - uint32_t offset, - uint32_t len) +static uint64_t packet_sum_partial(odp_packet_hdr_t *pkt_hdr, + uint32_t l3_offset, + uint32_t offset, + uint32_t len) { - uint32_t sum = 0; + uint64_t sum = 0; + uint32_t frame_len = odp_packet_len(packet_handle(pkt_hdr)); - if (offset + len > odp_packet_len(packet_handle(pkt_hdr))) + if (offset + len > frame_len) return 0; while (len > 0) { uint32_t seglen = 0; /* GCC */ - void *mapaddr = odp_packet_offset(packet_handle(pkt_hdr), - offset, &seglen, NULL); + void *mapaddr = odp_packet_offset(packet_handle(pkt_hdr), offset, &seglen, NULL); if (seglen > len) seglen = len; - sum += segment_sum16_32(mapaddr, seglen, offset); + sum += chksum_partial(mapaddr, seglen, offset - l3_offset); len -= seglen; offset += seglen; } @@ -1311,20 +1251,14 @@ static uint32_t packet_sum16_32(odp_packet_hdr_t *pkt_hdr, return sum; } -static uint16_t packet_sum_ones_comp16(odp_packet_hdr_t *pkt_hdr, - uint32_t offset, - uint32_t len, - uint32_t l4_part_sum) +static inline uint16_t packet_sum(odp_packet_hdr_t *pkt_hdr, + uint32_t l3_offset, + uint32_t offset, + uint32_t len, + uint64_t sum) { - uint32_t sum = l4_part_sum; - - sum += packet_sum16_32(pkt_hdr, offset, len); - - /* Not more than two additions */ - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - - return sum; + sum += packet_sum_partial(pkt_hdr, l3_offset, offset, len); + return chksum_finalize(sum); } static uint32_t packet_sum_crc32c(odp_packet_hdr_t *pkt_hdr, @@ -1441,7 +1375,7 @@ error: static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, uint32_t *offset, uint32_t frame_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_ipv4hdr_t *ipv4 = (const _odp_ipv4hdr_t *)*parseptr; uint32_t dstaddr = odp_be_to_cpu_32(ipv4->dst_addr); @@ -1459,7 +1393,7 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, if (chksums.chksum.ipv4) { prs->input_flags.l3_chksum_done = 1; - if (odp_chksum_ones_comp16(ipv4, ihl * 4) != 0xffff) { + if (chksum_finalize(chksum_partial(ipv4, ihl * 4, 0)) != 0xffff) { prs->flags.ip_err = 1; prs->flags.l3_chksum_err = 1; return 0; @@ -1470,8 +1404,8 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr, *parseptr += ihl * 4; if (chksums.chksum.udp || chksums.chksum.tcp) - *l4_part_sum = segment_sum16_32((const uint8_t *)&ipv4->src_addr, - 2 * _ODP_IPV4ADDR_LEN, 0); + *l4_part_sum = chksum_partial((const uint8_t *)&ipv4->src_addr, + 2 * _ODP_IPV4ADDR_LEN, 0); if (odp_unlikely(ihl > _ODP_IPV4HDR_IHL_MIN)) prs->input_flags.ipopt = 1; @@ -1501,7 +1435,7 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, uint32_t *offset, uint32_t frame_len, uint32_t seg_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_ipv6hdr_t *ipv6 = (const _odp_ipv6hdr_t *)*parseptr; const _odp_ipv6hdr_ext_t *ipv6ext; @@ -1525,8 +1459,8 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, *parseptr += sizeof(_odp_ipv6hdr_t); if (chksums.chksum.udp || chksums.chksum.tcp) - *l4_part_sum = segment_sum16_32((const uint8_t *)&ipv6->src_addr, - 2 * _ODP_IPV6ADDR_LEN, 0); + *l4_part_sum = chksum_partial((const uint8_t *)&ipv6->src_addr, + 2 * _ODP_IPV6ADDR_LEN, 0); /* Skip past any IPv6 extension headers */ if (ipv6->next_hdr == _ODP_IPPROTO_HOPOPTS || @@ -1569,7 +1503,7 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr, static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr, uint16_t tcp_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_tcphdr_t *tcp = (const _odp_tcphdr_t *)*parseptr; uint32_t len = tcp->hl * 4; @@ -1595,7 +1529,7 @@ static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr, */ static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { const _odp_udphdr_t *udp = (const _odp_udphdr_t *)*parseptr; uint32_t udplen = odp_be_to_cpu_16(udp->length); @@ -1642,7 +1576,7 @@ static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr, static inline void parse_sctp(packet_parser_t *prs, const uint8_t **parseptr, uint16_t sctp_len, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { if (odp_unlikely(sctp_len < sizeof(_odp_sctphdr_t))) { prs->flags.sctp_err = 1; @@ -1670,7 +1604,7 @@ int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr, uint32_t frame_len, uint32_t seg_len, int layer, uint16_t ethtype, odp_proto_chksums_t chksums, - uint32_t *l4_part_sum) + uint64_t *l4_part_sum) { uint8_t ip_proto; @@ -1783,7 +1717,7 @@ int _odp_packet_parse_common(packet_parser_t *prs, const uint8_t *ptr, uint32_t offset; uint16_t ethtype; const uint8_t *parseptr; - uint32_t l4_part_sum; + uint64_t l4_part_sum; parseptr = ptr; offset = 0; @@ -1820,7 +1754,7 @@ static inline int packet_ipv4_chksum(odp_packet_t pkt, if (odp_unlikely(res < 0)) return res; - *chksum = ~odp_chksum_ones_comp16(buf, nleft); + *chksum = ~chksum_finalize(chksum_partial(buf, nleft, 0)); return 0; } @@ -1868,7 +1802,7 @@ static int _odp_packet_tcp_udp_chksum_insert(odp_packet_t pkt, uint16_t proto) { odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); uint32_t zero = 0; - uint32_t sum; + uint64_t sum; uint16_t l3_ver; uint16_t chksum; uint32_t chksum_offset; @@ -1882,15 +1816,17 @@ static int _odp_packet_tcp_udp_chksum_insert(odp_packet_t pkt, uint16_t proto) odp_packet_copy_to_mem(pkt, pkt_hdr->p.l3_offset, 2, &l3_ver); if (_ODP_IPV4HDR_VER(l3_ver) == _ODP_IPV4) - sum = packet_sum16_32(pkt_hdr, - pkt_hdr->p.l3_offset + - _ODP_IPV4ADDR_OFFSSET, - 2 * _ODP_IPV4ADDR_LEN); + sum = packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l3_offset + + _ODP_IPV4ADDR_OFFSSET, + 2 * _ODP_IPV4ADDR_LEN); else - sum = packet_sum16_32(pkt_hdr, - pkt_hdr->p.l3_offset + - _ODP_IPV6ADDR_OFFSSET, - 2 * _ODP_IPV6ADDR_LEN); + sum = packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l3_offset + + _ODP_IPV6ADDR_OFFSSET, + 2 * _ODP_IPV6ADDR_LEN); #if ODP_BYTE_ORDER == ODP_BIG_ENDIAN sum += proto; #else @@ -1898,26 +1834,26 @@ static int _odp_packet_tcp_udp_chksum_insert(odp_packet_t pkt, uint16_t proto) #endif if (proto == _ODP_IPPROTO_TCP) { - sum += odp_cpu_to_be_16(frame_len - pkt_hdr->p.l4_offset); + sum += odp_cpu_to_be_16(frame_len - + pkt_hdr->p.l4_offset); chksum_offset = pkt_hdr->p.l4_offset + _ODP_UDP_CSUM_OFFSET; } else { - sum += packet_sum16_32(pkt_hdr, - pkt_hdr->p.l4_offset + - _ODP_UDP_LEN_OFFSET, - 2); + sum += packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset + + _ODP_UDP_LEN_OFFSET, + 2); chksum_offset = pkt_hdr->p.l4_offset + _ODP_UDP_CSUM_OFFSET; } odp_packet_copy_from_mem(pkt, chksum_offset, 2, &zero); - sum += packet_sum16_32(pkt_hdr, - pkt_hdr->p.l4_offset, - frame_len - pkt_hdr->p.l4_offset); - - /* Not more than two additions */ - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); + sum += packet_sum_partial(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset, + frame_len - + pkt_hdr->p.l4_offset); - chksum = ~sum; + chksum = ~chksum_finalize(sum); if (proto == _ODP_IPPROTO_UDP && chksum == 0) chksum = 0xffff; @@ -1965,7 +1901,7 @@ int _odp_packet_sctp_chksum_insert(odp_packet_t pkt) { odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt); uint32_t sum; - uint32_t len = odp_packet_len(pkt); + uint32_t frame_len = odp_packet_len(pkt); if (pkt_hdr->p.l4_offset == ODP_PACKET_OFFSET_INVALID) return -1; @@ -1973,26 +1909,28 @@ int _odp_packet_sctp_chksum_insert(odp_packet_t pkt) sum = 0; odp_packet_copy_from_mem(pkt, pkt_hdr->p.l4_offset + 8, 4, &sum); sum = ~packet_sum_crc32c(pkt_hdr, pkt_hdr->p.l4_offset, - len - pkt_hdr->p.l4_offset, ~0); + frame_len - pkt_hdr->p.l4_offset, + ~0); return odp_packet_copy_from_mem(pkt, pkt_hdr->p.l4_offset + 8, 4, &sum); } static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, odp_proto_chksums_t chksums, - uint32_t l4_part_sum) + uint64_t l4_part_sum) { - uint32_t len = odp_packet_len(packet_handle(pkt_hdr)); + uint32_t frame_len = odp_packet_len(packet_handle(pkt_hdr)); /* UDP chksum == 0 case is covered in parse_udp() */ if (chksums.chksum.udp && pkt_hdr->p.input_flags.udp && !pkt_hdr->p.input_flags.ipfrag && !pkt_hdr->p.input_flags.udp_chksum_zero) { - uint16_t sum = ~packet_sum_ones_comp16(pkt_hdr, - pkt_hdr->p.l4_offset, - len - - pkt_hdr->p.l4_offset, - l4_part_sum); + uint16_t sum = ~packet_sum(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset, + frame_len - + pkt_hdr->p.l4_offset, + l4_part_sum); pkt_hdr->p.input_flags.l4_chksum_done = 1; if (sum != 0) { @@ -2005,11 +1943,12 @@ static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, if (chksums.chksum.tcp && pkt_hdr->p.input_flags.tcp && !pkt_hdr->p.input_flags.ipfrag) { - uint16_t sum = ~packet_sum_ones_comp16(pkt_hdr, - pkt_hdr->p.l4_offset, - len - - pkt_hdr->p.l4_offset, - l4_part_sum); + uint16_t sum = ~packet_sum(pkt_hdr, + pkt_hdr->p.l3_offset, + pkt_hdr->p.l4_offset, + frame_len - + pkt_hdr->p.l4_offset, + l4_part_sum); pkt_hdr->p.input_flags.l4_chksum_done = 1; if (sum != 0) { @@ -2025,7 +1964,7 @@ static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, uint32_t sum = ~packet_sum_crc32c(pkt_hdr, pkt_hdr->p.l4_offset + _ODP_SCTPHDR_LEN, - len - + frame_len - pkt_hdr->p.l4_offset - _ODP_SCTPHDR_LEN, l4_part_sum); @@ -2058,7 +1997,7 @@ int _odp_packet_parse_layer(odp_packet_hdr_t *pkt_hdr, const uint8_t *base = odp_packet_data(pkt); uint32_t offset = 0; uint16_t ethtype; - uint32_t l4_part_sum = 0; + uint64_t l4_part_sum = 0; int rc; if (odp_unlikely(layer == ODP_PROTO_LAYER_NONE)) @@ -2094,7 +2033,7 @@ int odp_packet_parse(odp_packet_t pkt, uint32_t offset, odp_proto_layer_t layer = param->last_layer; int ret; uint16_t ethtype; - uint32_t l4_part_sum = 0; + uint64_t l4_part_sum = 0; if (proto == ODP_PROTO_NONE || layer == ODP_PROTO_LAYER_NONE) return -1; -- cgit v1.2.3 From 8eeae45499b0022f9a64e34685748461b35e046a Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 21 Apr 2021 08:45:22 +0300 Subject: Port 84b658753 "helper: add CLI helper API and implementation" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/m4/configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/linux-dpdk/m4/configure.m4 b/platform/linux-dpdk/m4/configure.m4 index 3bf091082..b86bbbbb5 100644 --- a/platform/linux-dpdk/m4/configure.m4 +++ b/platform/linux-dpdk/m4/configure.m4 @@ -61,7 +61,7 @@ esac # Required for experimental rte_event_port_unlinks_in_progress() API DPDK_CFLAGS="${DPDK_CFLAGS} -DALLOW_EXPERIMENTAL_API" -AS_VAR_APPEND([PLAT_DEP_LIBS], ["${LIBCONFIG_LIBS} ${OPENSSL_LIBS} ${DPDK_LIBS_LT}"]) +AS_VAR_APPEND([PLAT_DEP_LIBS], ["${LIBCONFIG_LIBS} ${OPENSSL_LIBS} ${DPDK_LIBS_LT} ${LIBCLI_LIBS}"]) # Add text to the end of configure with platform specific settings. # Make sure it's aligned same as other lines in configure.ac. -- cgit v1.2.3 From 0ae8eb51a0d22fa90437a4ecf15aa62eaf22bb6e Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 21 Apr 2021 08:47:31 +0300 Subject: Port 418e577a4 "linux-gen: atomic: add 128 bit atomic apis" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am index bb44c8661..38a0258a0 100644 --- a/platform/linux-dpdk/Makefile.am +++ b/platform/linux-dpdk/Makefile.am @@ -257,7 +257,8 @@ odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \ arch/default/odp/api/abi/cpu_time.h \ arch/aarch64/odp/api/abi/hash_crc32.h if !ODP_ABI_COMPAT -odpapiabiarchinclude_HEADERS += arch/aarch64/odp/api/abi/cpu.h +odpapiabiarchinclude_HEADERS += arch/aarch64/odp/api/abi/atomic.h \ + arch/aarch64/odp/api/abi/cpu.h endif noinst_HEADERS += arch/aarch64/odp_atomic.h \ arch/aarch64/odp_cpu.h \ -- cgit v1.2.3 From 116ec73a81f18afe15de02a9c3b575947270375f Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 21 Apr 2021 08:52:34 +0300 Subject: Port a1a2a326a "linux-gen: timer: change user pointer to const" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/odp_timer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/linux-dpdk/odp_timer.c b/platform/linux-dpdk/odp_timer.c index 5ae6fa77c..7376ee0ca 100644 --- a/platform/linux-dpdk/odp_timer.c +++ b/platform/linux-dpdk/odp_timer.c @@ -1,5 +1,5 @@ /* Copyright (c) 2018, Linaro Limited - * Copyright (c) 2019-2020, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -69,7 +69,7 @@ typedef struct { odp_ticketlock_t lock; int state; uint64_t tick; - void *user_ptr; + const void *user_ptr; odp_queue_t queue; odp_event_t tmo_event; struct timer_pool_s *timer_pool; @@ -507,7 +507,7 @@ uint64_t odp_timer_pool_to_u64(odp_timer_pool_t tp) odp_timer_t odp_timer_alloc(odp_timer_pool_t tp, odp_queue_t queue, - void *user_ptr) + const void *user_ptr) { uint32_t timer_idx; timer_entry_t *timer; @@ -811,7 +811,7 @@ void *odp_timeout_user_ptr(odp_timeout_t tmo) { odp_timeout_hdr_t *timeout_hdr = timeout_to_hdr(tmo); - return timeout_hdr->user_ptr; + return (void *)(uintptr_t)timeout_hdr->user_ptr; } odp_timeout_t odp_timeout_alloc(odp_pool_t pool) -- cgit v1.2.3 From f3db3a43c05847aa81d91cdb5889b6d479e18090 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 21 Apr 2021 09:27:58 +0300 Subject: Port 5e5137828 "linux-gen: timer: implement debug print functions" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/odp_timer.c | 73 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/platform/linux-dpdk/odp_timer.c b/platform/linux-dpdk/odp_timer.c index 7376ee0ca..0910d09ac 100644 --- a/platform/linux-dpdk/odp_timer.c +++ b/platform/linux-dpdk/odp_timer.c @@ -829,3 +829,76 @@ void odp_timeout_free(odp_timeout_t tmo) odp_buffer_free(odp_buffer_from_event(ev)); } + +void odp_timer_pool_print(odp_timer_pool_t timer_pool) +{ + timer_pool_t *tp; + + if (timer_pool == ODP_TIMER_POOL_INVALID) { + ODP_ERR("Bad timer pool handle\n"); + return; + } + + tp = timer_pool_from_hdl(timer_pool); + + ODP_PRINT("\nTimer pool info\n"); + ODP_PRINT("---------------\n"); + ODP_PRINT(" timer pool %p\n", tp); + ODP_PRINT(" name %s\n", tp->name); + ODP_PRINT(" num timers %u\n", tp->cur_timers); + ODP_PRINT(" hwm timers %u\n", tp->hwm_timers); + ODP_PRINT(" num tp %i\n", timer_global->num_timer_pools); + ODP_PRINT("\n"); +} + +void odp_timer_print(odp_timer_t timer_hdl) +{ + timer_entry_t *timer = timer_from_hdl(timer_hdl); + + if (timer_hdl == ODP_TIMER_INVALID) { + ODP_ERR("Bad timer handle\n"); + return; + } + + ODP_PRINT("\nTimer info\n"); + ODP_PRINT("----------\n"); + ODP_PRINT(" timer pool %p\n", timer->timer_pool); + ODP_PRINT(" timer index %" PRIu32 "\n", timer->timer_idx); + ODP_PRINT(" dest queue 0x%" PRIx64 "\n", odp_queue_to_u64(timer->queue)); + ODP_PRINT(" user ptr %p\n", timer->user_ptr); + ODP_PRINT(" state %s\n", + (timer->state == NOT_TICKING) ? "not ticking" : + (timer->state == EXPIRED ? "expired" : "ticking")); + ODP_PRINT("\n"); +} + +void odp_timeout_print(odp_timeout_t tmo) +{ + const odp_timeout_hdr_t *timeout_hdr = timeout_to_hdr(tmo); + odp_timer_t timer_hdl; + timer_pool_t *tp = NULL; + uint32_t idx = 0; + + if (tmo == ODP_TIMEOUT_INVALID) { + ODP_ERR("Bad timeout handle\n"); + return; + } + + timer_hdl = timeout_hdr->timer; + + if (timer_hdl != ODP_TIMER_INVALID) { + timer_entry_t *timer = timer_from_hdl(timer_hdl); + + tp = timer->timer_pool; + idx = timer->timer_idx; + } + + ODP_PRINT("\nTimeout info\n"); + ODP_PRINT("------------\n"); + ODP_PRINT(" tmo handle 0x%" PRIx64 "\n", odp_timeout_to_u64(tmo)); + ODP_PRINT(" timer pool %p\n", tp); + ODP_PRINT(" timer index %u\n", idx); + ODP_PRINT(" expiration %" PRIu64 "\n", timeout_hdr->expiration); + ODP_PRINT(" user ptr %p\n", timeout_hdr->user_ptr); + ODP_PRINT("\n"); +} -- cgit v1.2.3 From 20eb6b4655671fbfb6fd41c7407762cd30f1cfc5 Mon Sep 17 00:00:00 2001 From: Matias Elo Date: Wed, 21 Apr 2021 09:51:45 +0300 Subject: Port 72e450dd3 "linux-gen: queue: implement odp_queue_print_all" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port original commit from linux-generic. Signed-off-by: Matias Elo Reviewed-by: Jere Leppänen --- platform/linux-dpdk/odp_queue_basic.c | 96 ++++++++++++++++++++++++++++++++++- platform/linux-dpdk/odp_queue_if.c | 9 +++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/platform/linux-dpdk/odp_queue_basic.c b/platform/linux-dpdk/odp_queue_basic.c index a006bcc54..4cf619965 100644 --- a/platform/linux-dpdk/odp_queue_basic.c +++ b/platform/linux-dpdk/odp_queue_basic.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -726,6 +727,97 @@ static void queue_print(odp_queue_t handle) UNLOCK(queue); } +static void queue_print_all(void) +{ + uint32_t i, index, len, max_len; + const char *name; + int status; + odp_queue_type_t type; + odp_nonblocking_t blocking; + odp_queue_op_mode_t enq_mode; + odp_queue_op_mode_t deq_mode; + odp_queue_order_t order; + const char *status_str; + const char *bl_str; + char type_c, enq_c, deq_c, order_c, sync_c; + const int col_width = 24; + int prio = 0; + odp_schedule_sync_t sync = ODP_SCHED_SYNC_PARALLEL; + + ODP_PRINT("\nList of all queues\n"); + ODP_PRINT("------------------\n"); + ODP_PRINT(" idx %-*s type stat blk enq deq ord len max_len sync prio\n", col_width, "name"); + + for (i = 0; i < CONFIG_MAX_QUEUES; i++) { + queue_entry_t *queue = qentry_from_index(i); + + if (queue->s.status < QUEUE_STATUS_READY) + continue; + + LOCK(queue); + + status = queue->s.status; + index = queue->s.index; + name = queue->s.name; + type = queue->s.type; + blocking = queue->s.param.nonblocking; + enq_mode = queue->s.param.enq_mode; + deq_mode = queue->s.param.deq_mode; + order = queue->s.param.order; + + if (queue->s.queue_lf) { + len = _odp_queue_lf_length(queue->s.queue_lf); + max_len = _odp_queue_lf_max_length(); + } else if (queue->s.spsc) { + len = ring_spsc_length(queue->s.ring_spsc); + max_len = ring_spsc_max_length(queue->s.ring_spsc); + } else if (type == ODP_QUEUE_TYPE_SCHED) { + len = ring_st_length(queue->s.ring_st); + max_len = ring_st_max_length(queue->s.ring_st); + prio = queue->s.param.sched.prio; + sync = queue->s.param.sched.sync; + } else { + len = ring_mpmc_length(queue->s.ring_mpmc); + max_len = ring_mpmc_max_length(queue->s.ring_mpmc); + } + + UNLOCK(queue); + + if (status < QUEUE_STATUS_READY) + continue; + + status_str = (status == QUEUE_STATUS_READY) ? "R" : + ((status == QUEUE_STATUS_SCHED) ? "S" : "NS"); + + type_c = (type == ODP_QUEUE_TYPE_PLAIN) ? 'P' : 'S'; + + bl_str = (blocking == ODP_BLOCKING) ? "B" : + ((blocking == ODP_NONBLOCKING_LF) ? "LF" : "WF"); + + enq_c = (enq_mode == ODP_QUEUE_OP_MT) ? 'S' : + ((enq_mode == ODP_QUEUE_OP_MT_UNSAFE) ? 'U' : 'D'); + + deq_c = (deq_mode == ODP_QUEUE_OP_MT) ? 'S' : + ((deq_mode == ODP_QUEUE_OP_MT_UNSAFE) ? 'U' : 'D'); + + order_c = (order == ODP_QUEUE_ORDER_KEEP) ? 'K' : 'I'; + + ODP_PRINT("%4u %-*s %c %2s %2s", index, col_width, name, type_c, + status_str, bl_str); + ODP_PRINT(" %c %c %c %6u %6u", enq_c, deq_c, order_c, len, max_len); + + if (type == ODP_QUEUE_TYPE_SCHED) { + sync_c = (sync == ODP_SCHED_SYNC_PARALLEL) ? 'P' : + ((sync == ODP_SCHED_SYNC_ATOMIC) ? 'A' : 'O'); + ODP_PRINT(" %c %4i", sync_c, prio); + } + + ODP_PRINT("\n"); + } + + ODP_PRINT("\n"); +} + static inline int _sched_queue_enq_multi(odp_queue_t handle, odp_buffer_hdr_t *buf_hdr[], int num) { @@ -1094,7 +1186,9 @@ _odp_queue_api_fn_t queue_basic_api = { .queue_to_u64 = queue_to_u64, .queue_param_init = queue_param_init, .queue_info = queue_info, - .queue_print = queue_print + .queue_print = queue_print, + .queue_print_all = queue_print_all + }; /* Functions towards internal components */ diff --git a/platform/linux-dpdk/odp_queue_if.c b/platform/linux-dpdk/odp_queue_if.c index f19716d73..310664fb8 100644 --- a/platform/linux-dpdk/odp_queue_if.c +++ b/platform/linux-dpdk/odp_queue_if.c @@ -88,7 +88,7 @@ uint64_t odp_queue_to_u64(odp_queue_t hdl) void odp_queue_param_init(odp_queue_param_t *param) { - return _odp_queue_api->queue_param_init(param); + _odp_queue_api->queue_param_init(param); } int odp_queue_info(odp_queue_t queue, odp_queue_info_t *info) @@ -98,7 +98,12 @@ int odp_queue_info(odp_queue_t queue, odp_queue_info_t *info) void odp_queue_print(odp_queue_t queue) { - return _odp_queue_api->queue_print(queue); + _odp_queue_api->queue_print(queue); +} + +void odp_queue_print_all(void) +{ + _odp_queue_api->queue_print_all(); } int _odp_queue_init_global(void) -- cgit v1.2.3