From 5205954791cb96244904f2c904a75d29a9bbf31b Mon Sep 17 00:00:00 2001 From: Cristian Dumitrescu Date: Wed, 4 Jun 2014 19:08:39 +0100 Subject: [PATCH] app/test: packet framework unit tests Unit tests for Packet Framework libraries. Signed-off-by: Cristian Dumitrescu Tested-by: Waterman Cao Acked-by: Pablo de Lara Guarch Acked by: Ivan Boule --- app/test/Makefile | 6 + app/test/commands.c | 4 +- app/test/test.h | 1 + app/test/test_table.c | 220 +++++ app/test/test_table.h | 204 +++++ app/test/test_table_acl.c | 593 +++++++++++++ app/test/test_table_acl.h | 35 + app/test/test_table_combined.c | 784 +++++++++++++++++ app/test/test_table_combined.h | 55 ++ app/test/test_table_pipeline.c | 603 +++++++++++++ app/test/test_table_pipeline.h | 35 + app/test/test_table_ports.c | 224 +++++ app/test/test_table_ports.h | 42 + app/test/test_table_tables.c | 907 ++++++++++++++++++++ app/test/test_table_tables.h | 50 ++ lib/librte_eal/common/include/rte_hexdump.h | 2 + 16 files changed, 3764 insertions(+), 1 deletion(-) create mode 100644 app/test/test_table.c create mode 100644 app/test/test_table.h create mode 100644 app/test/test_table_acl.c create mode 100644 app/test/test_table_acl.h create mode 100644 app/test/test_table_combined.c create mode 100644 app/test/test_table_combined.h create mode 100644 app/test/test_table_pipeline.c create mode 100644 app/test/test_table_pipeline.h create mode 100644 app/test/test_table_ports.c create mode 100644 app/test/test_table_ports.h create mode 100644 app/test/test_table_tables.c create mode 100644 app/test/test_table_tables.h diff --git a/app/test/Makefile b/app/test/Makefile index 3b050c3dd3..9c524602e4 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -52,6 +52,12 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_spinlock.c SRCS-$(CONFIG_RTE_APP_TEST) += test_memory.c SRCS-$(CONFIG_RTE_APP_TEST) += test_memzone.c SRCS-$(CONFIG_RTE_APP_TEST) += test_ring.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_table.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_table_pipeline.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_table_tables.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_table_ports.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_table_combined.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_table_acl.c SRCS-$(CONFIG_RTE_APP_TEST) += test_ring_perf.c SRCS-$(CONFIG_RTE_APP_TEST) += test_rwlock.c SRCS-$(CONFIG_RTE_APP_TEST) += test_timer.c diff --git a/app/test/commands.c b/app/test/commands.c index 016410d55b..c9dc0850a7 100644 --- a/app/test/commands.c +++ b/app/test/commands.c @@ -151,6 +151,8 @@ static void cmd_autotest_parsed(void *parsed_result, ret = test_cycles(); if (!strcmp(res->autotest, "ring_autotest")) ret = test_ring(); + if (!strcmp(res->autotest, "table_autotest")) + ret = test_table(); if (!strcmp(res->autotest, "ring_perf_autotest")) ret = test_ring_perf(); if (!strcmp(res->autotest, "timer_autotest")) @@ -230,7 +232,7 @@ cmdline_parse_token_string_t cmd_autotest_autotest = "red_autotest#meter_autotest#sched_autotest#" "memcpy_perf_autotest#kni_autotest#" "pm_autotest#ivshmem_autotest#" - "devargs_autotest#" + "devargs_autotest#table_autotest#" #ifdef RTE_LIBRTE_ACL "acl_autotest#" #endif diff --git a/app/test/test.h b/app/test/test.h index f992ceba91..c54e7ef3bf 100644 --- a/app/test/test.h +++ b/app/test/test.h @@ -57,6 +57,7 @@ int test_cycles(void); int test_logs(void); int test_memzone(void); int test_ring(void); +int test_table(void); int test_ring_perf(void); int test_mempool(void); int test_mempool_perf(void); diff --git a/app/test/test_table.c b/app/test/test_table.c new file mode 100644 index 0000000000..7e2e781d5c --- /dev/null +++ b/app/test/test_table.c @@ -0,0 +1,220 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + + +#ifndef RTE_LIBRTE_TABLE + +#include "test.h" + +int +test_table(void) +{ + return 0; +} + +#else + +#include +#include +#include +#include +#include "test.h" +#include "test_table.h" +#include "test_table_pipeline.h" +#include "test_table_ports.h" +#include "test_table_tables.h" +#include "test_table_combined.h" +#include "test_table_acl.h" + +/* Global variables */ +struct rte_pipeline *p; +struct rte_ring *rings_rx[N_PORTS]; +struct rte_ring *rings_tx[N_PORTS]; +struct rte_mempool *pool = NULL; + +uint32_t port_in_id[N_PORTS]; +uint32_t port_out_id[N_PORTS]; +uint32_t port_out_id_type[3]; +uint32_t table_id[N_PORTS*2]; +uint64_t override_hit_mask = 0xFFFFFFFF; +uint64_t override_miss_mask = 0xFFFFFFFF; +uint64_t non_reserved_actions_hit = 0; +uint64_t non_reserved_actions_miss = 0; +uint8_t connect_miss_action_to_port_out = 0; +uint8_t connect_miss_action_to_table = 0; +uint32_t table_entry_default_action = RTE_PIPELINE_ACTION_DROP; +uint32_t table_entry_hit_action = RTE_PIPELINE_ACTION_PORT; +uint32_t table_entry_miss_action = RTE_PIPELINE_ACTION_DROP; +rte_pipeline_port_in_action_handler port_in_action = NULL; +rte_pipeline_port_out_action_handler port_out_action = NULL; +rte_pipeline_table_action_handler_hit action_handler_hit = NULL; +rte_pipeline_table_action_handler_miss action_handler_miss = NULL; + +/* Function prototypes */ +static void app_init_rings(void); +static void app_init_mbuf_pools(void); + +uint64_t pipeline_test_hash(void *key, + __attribute__((unused)) uint32_t key_size, + __attribute__((unused)) uint64_t seed) +{ + uint32_t *k32 = (uint32_t *) key; + uint32_t ip_dst = rte_be_to_cpu_32(k32[0]); + uint64_t signature = ip_dst; + + return signature; +} + +static void +app_init_mbuf_pools(void) +{ + /* Init the buffer pool */ + printf("Getting/Creating the mempool ...\n"); + pool = rte_mempool_lookup("mempool"); + if (!pool) { + pool = rte_mempool_create( + "mempool", + POOL_SIZE, + POOL_BUFFER_SIZE, + POOL_CACHE_SIZE, + sizeof(struct rte_pktmbuf_pool_private), + rte_pktmbuf_pool_init, NULL, + rte_pktmbuf_init, NULL, + 0, + 0); + if (pool == NULL) + rte_panic("Cannot create mbuf pool\n"); + } +} + +static void +app_init_rings(void) +{ + uint32_t i; + + for (i = 0; i < N_PORTS; i++) { + char name[32]; + + rte_snprintf(name, sizeof(name), "app_ring_rx_%u", i); + rings_rx[i] = rte_ring_lookup(name); + if (rings_rx[i] == NULL) { + rings_rx[i] = rte_ring_create( + name, + RING_RX_SIZE, + 0, + RING_F_SP_ENQ | RING_F_SC_DEQ); + } + if (rings_rx[i] == NULL) + rte_panic("Cannot create RX ring %u\n", i); + } + + for (i = 0; i < N_PORTS; i++) { + char name[32]; + + rte_snprintf(name, sizeof(name), "app_ring_tx_%u", i); + rings_tx[i] = rte_ring_lookup(name); + if (rings_tx[i] == NULL) { + rings_tx[i] = rte_ring_create( + name, + RING_TX_SIZE, + 0, + RING_F_SP_ENQ | RING_F_SC_DEQ); + } + if (rings_tx[i] == NULL) + rte_panic("Cannot create TX ring %u\n", i); + } + +} + +int +test_table(void) +{ + int status, failures; + unsigned i; + + failures = 0; + + app_init_rings(); + app_init_mbuf_pools(); + + printf("\n\n\n\n************Pipeline tests************\n"); + + if (test_table_pipeline() < 0) + return -1; + + printf("\n\n\n\n************Port tests************\n"); + for (i = 0; i < n_port_tests; i++) { + status = port_tests[i](); + if (status < 0) { + printf("\nPort test number %d failed (%d).\n", i, + status); + failures++; + return -1; + } + } + + printf("\n\n\n\n************Table tests************\n"); + for (i = 0; i < n_table_tests; i++) { + status = table_tests[i](); + if (status < 0) { + printf("\nTable test number %d failed (%d).\n", i, + status); + failures++; + return -1; + } + } + + printf("\n\n\n\n************Table tests************\n"); + for (i = 0; i < n_table_tests_combined; i++) { + status = table_tests_combined[i](); + if (status < 0) { + printf("\nCombined table test number %d failed with " + "reason number %d.\n", i, status); + failures++; + return -1; + } + } + + if (failures) + return -1; + +#ifdef RTE_LIBRTE_ACL + printf("\n\n\n\n************ACL tests************\n"); + if (test_table_ACL() < 0) + return -1; +#endif + + return 0; +} + +#endif diff --git a/app/test/test_table.h b/app/test/test_table.h new file mode 100644 index 0000000000..afea738271 --- /dev/null +++ b/app/test/test_table.h @@ -0,0 +1,204 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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 +#include + +#ifdef RTE_LIBRTE_ACL +#include +#endif + +#include +#include +#include + +#ifndef TEST_TABLE_H_ +#define TEST_TABLE_H_ + +#define RING_SIZE 4096 +#define MAX_BULK 32 +#define N 65536 +#define TIME_S 5 +#define TEST_RING_FULL_EMTPY_ITER 8 +#define N_PORTS 2 +#define N_PKTS 2 +#define N_PKTS_EXT 6 +#define RING_RX rings_rx[0] +#define RING_RX_2 rings_rx[1] +#define RING_TX rings_tx[0] +#define RING_TX_2 rings_tx[1] +#define PORT_RX_RING_SIZE 128 +#define PORT_TX_RING_SIZE 512 +#define RING_RX_SIZE 128 +#define RING_TX_SIZE 128 +#define POOL_BUFFER_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) +#define POOL_SIZE (32 * 1024) +#define POOL_CACHE_SIZE 256 +#define BURST_SIZE 8 +#define WORKER_TYPE 1 +#define MAX_DUMMY_PORTS 2 +#define MP_NAME "dummy_port_mempool" +#define MBUF_COUNT (8000 * MAX_DUMMY_PORTS) +#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) +#define MP_CACHE_SZ 256 +#define MP_SOCKET 0 +#define MP_FLAGS 0 + +/* Macros */ +#define RING_ENQUEUE(ring, value) do { \ + struct rte_mbuf *m; \ + uint32_t *k32, *signature; \ + uint8_t *key; \ + \ + m = rte_pktmbuf_alloc(pool); \ + if (m == NULL) \ + return -1; \ + signature = RTE_MBUF_METADATA_UINT32_PTR(m, 0); \ + key = RTE_MBUF_METADATA_UINT8_PTR(m, 32); \ + k32 = (uint32_t *) key; \ + k32[0] = (value); \ + *signature = pipeline_test_hash(key, 0, 0); \ + rte_ring_enqueue((ring), m); \ +} while (0) + +#define RUN_PIPELINE(pipeline) do { \ + rte_pipeline_run((pipeline)); \ + rte_pipeline_flush((pipeline)); \ +} while (0) + +#define VERIFY(var, value) do { \ + if ((var) != -(value)) \ + return var; \ +} while (0) + +#define VERIFY_TRAFFIC(ring, sent, expected) do { \ + unsigned i, n = 0; \ + void *mbuf = NULL; \ + \ + for (i = 0; i < (sent); i++) { \ + if (!rte_ring_dequeue((ring), &mbuf)) { \ + if (mbuf == NULL) \ + continue; \ + n++; \ + rte_pktmbuf_free((struct rte_mbuf *)mbuf); \ + } \ + else \ + break; \ + } \ + printf("Expected %d, got %d\n", expected, n); \ + if (n != (expected)) { \ + return -21; \ + } \ +} while (0) + +/* Function definitions */ +int test_table(void); +uint64_t pipeline_test_hash( + void *key, + __attribute__((unused)) uint32_t key_size, + __attribute__((unused)) uint64_t seed); + +/* Extern variables */ +extern struct rte_pipeline *p; +extern struct rte_ring *rings_rx[N_PORTS]; +extern struct rte_ring *rings_tx[N_PORTS]; +extern struct rte_mempool *pool; +extern uint32_t port_in_id[N_PORTS]; +extern uint32_t port_out_id[N_PORTS]; +extern uint32_t port_out_id_type[3]; +extern uint32_t table_id[N_PORTS*2]; +extern uint64_t override_hit_mask; +extern uint64_t override_miss_mask; +extern uint64_t non_reserved_actions_hit; +extern uint64_t non_reserved_actions_miss; +extern uint8_t connect_miss_action_to_port_out; +extern uint8_t connect_miss_action_to_table; +extern uint32_t table_entry_default_action; +extern uint32_t table_entry_hit_action; +extern uint32_t table_entry_miss_action; +extern rte_pipeline_port_in_action_handler port_in_action; +extern rte_pipeline_port_out_action_handler port_out_action; +extern rte_pipeline_table_action_handler_hit action_handler_hit; +extern rte_pipeline_table_action_handler_miss action_handler_miss; + +/* Global data types */ +struct manage_ops { + uint32_t op_id; + void *op_data; + int expected_result; +}; + +/* Internal pipeline structures */ +struct rte_port_in { + struct rte_port_in_ops ops; + uint32_t burst_size; + uint32_t table_id; + void *h_port; +}; + +struct rte_port_out { + struct rte_port_out_ops ops; + void *h_port; +}; + +struct rte_table { + struct rte_table_ops ops; + rte_pipeline_table_action_handler_hit f_action; + uint32_t table_next_id; + uint32_t table_next_id_valid; + uint8_t actions_lookup_miss[CACHE_LINE_SIZE]; + uint32_t action_data_size; + void *h_table; +}; + +#define RTE_PIPELINE_MAX_NAME_SZ 124 + +struct rte_pipeline { + char name[RTE_PIPELINE_MAX_NAME_SZ]; + uint32_t socket_id; + struct rte_port_in ports_in[16]; + struct rte_port_out ports_out[16]; + struct rte_table tables[64]; + uint32_t num_ports_in; + uint32_t num_ports_out; + uint32_t num_tables; + struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX]; + struct rte_table_entry *actions[RTE_PORT_IN_BURST_SIZE_MAX]; + uint64_t mask_action[64]; + uint32_t mask_actions; +}; +#endif diff --git a/app/test/test_table_acl.c b/app/test/test_table_acl.c new file mode 100644 index 0000000000..afc234af3e --- /dev/null +++ b/app/test/test_table_acl.c @@ -0,0 +1,593 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +#ifdef RTE_LIBRTE_ACL + +#include +#include "test_table.h" +#include "test_table_acl.h" + +#define IPv4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | \ + (((b) & 0xff) << 16) | \ + (((c) & 0xff) << 8) | \ + ((d) & 0xff)) + +static const char cb_port_delim[] = ":"; + +/* + * Rule and trace formats definitions. + **/ + +struct ipv4_5tuple { + uint8_t proto; + uint32_t ip_src; + uint32_t ip_dst; + uint16_t port_src; + uint16_t port_dst; +}; + +enum { + PROTO_FIELD_IPV4, + SRC_FIELD_IPV4, + DST_FIELD_IPV4, + SRCP_FIELD_IPV4, + DSTP_FIELD_IPV4, + NUM_FIELDS_IPV4 +}; + +struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = PROTO_FIELD_IPV4, + .input_index = PROTO_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, proto), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC_FIELD_IPV4, + .input_index = SRC_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, ip_src), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST_FIELD_IPV4, + .input_index = DST_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, ip_dst), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = SRCP_FIELD_IPV4, + .input_index = SRCP_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, port_src), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = DSTP_FIELD_IPV4, + .input_index = SRCP_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, port_dst), + }, +}; + +struct rte_table_acl_rule_add_params table_acl_IPv4_rule; + +typedef int (*parse_5tuple)(char *text, + struct rte_table_acl_rule_add_params *rule); + +/* +* The order of the fields in the rule string after the initial '@' +*/ +enum { + CB_FLD_SRC_ADDR, + CB_FLD_DST_ADDR, + CB_FLD_SRC_PORT_RANGE, + CB_FLD_DST_PORT_RANGE, + CB_FLD_PROTO, + CB_FLD_NUM, +}; + + +#define GET_CB_FIELD(in, fd, base, lim, dlm) \ +do { \ + unsigned long val; \ + char *end; \ + \ + errno = 0; \ + val = strtoul((in), &end, (base)); \ + if (errno != 0 || end[0] != (dlm) || val > (lim)) \ + return -EINVAL; \ + (fd) = (typeof(fd)) val; \ + (in) = end + 1; \ +} while (0) + + + + +static int +parse_ipv4_net(const char *in, uint32_t *addr, uint32_t *mask_len) +{ + uint8_t a, b, c, d, m; + + GET_CB_FIELD(in, a, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, b, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, c, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, d, 0, UINT8_MAX, '/'); + GET_CB_FIELD(in, m, 0, sizeof(uint32_t) * CHAR_BIT, 0); + + addr[0] = IPv4(a, b, c, d); + mask_len[0] = m; + + return 0; +} + +static int +parse_port_range(const char *in, uint16_t *port_low, uint16_t *port_high) +{ + uint16_t a, b; + + GET_CB_FIELD(in, a, 0, UINT16_MAX, ':'); + GET_CB_FIELD(in, b, 0, UINT16_MAX, 0); + + port_low[0] = a; + port_high[0] = b; + + return 0; +} + +static int +parse_cb_ipv4_rule(char *str, struct rte_table_acl_rule_add_params *v) +{ + int i, rc; + char *s, *sp, *in[CB_FLD_NUM]; + static const char *dlm = " \t\n"; + + /* + ** Skip leading '@' + */ + if (strchr(str, '@') != str) + return -EINVAL; + + s = str + 1; + + /* + * Populate the 'in' array with the location of each + * field in the string we're parsing + */ + for (i = 0; i != DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR], + &v->field_value[SRC_FIELD_IPV4].value.u32, + &v->field_value[SRC_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read src address/mask: %s\n", + in[CB_FLD_SRC_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRC_FIELD_IPV4].value.u32, + v->field_value[SRC_FIELD_IPV4].mask_range.u32); + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_DST_ADDR], + &v->field_value[DST_FIELD_IPV4].value.u32, + &v->field_value[DST_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest address/mask: %s\n", + in[CB_FLD_DST_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DST_FIELD_IPV4].value.u32, + v->field_value[DST_FIELD_IPV4].mask_range.u32); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_SRC_PORT_RANGE], + &v->field_value[SRCP_FIELD_IPV4].value.u16, + &v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read source port range: %s\n", + in[CB_FLD_SRC_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRCP_FIELD_IPV4].value.u16, + v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_DST_PORT_RANGE], + &v->field_value[DSTP_FIELD_IPV4].value.u16, + &v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest port range: %s\n", + in[CB_FLD_DST_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DSTP_FIELD_IPV4].value.u16, + v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + /* parse 0/0xnn */ + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].value.u8, + 0, UINT8_MAX, '/'); + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].mask_range.u8, + 0, UINT8_MAX, 0); + + printf("V=%u, mask=%u\n", + (unsigned int)v->field_value[PROTO_FIELD_IPV4].value.u8, + v->field_value[PROTO_FIELD_IPV4].mask_range.u8); + return 0; +} + + +/* + * The format for these rules DO NOT need the port ranges to be + * separated by ' : ', just ':'. It's a lot more readable and + * cleaner, IMO. + */ +char lines[][128] = { + "@0.0.0.0/0 0.0.0.0/0 0:65535 0:65535 2/0xff", /* Protocol check */ + "@192.168.3.1/32 0.0.0.0/0 0:65535 0:65535 0/0", /* Src IP checl */ + "@0.0.0.0/0 10.4.4.1/32 0:65535 0:65535 0/0", /* dst IP check */ + "@0.0.0.0/0 0.0.0.0/0 105:105 0:65535 0/0", /* src port check */ + "@0.0.0.0/0 0.0.0.0/0 0:65535 206:206 0/0", /* dst port check */ +}; + +char line[128]; + + +static int +setup_acl_pipeline(void) +{ + int ret; + int i; + struct rte_pipeline_params pipeline_params = { + .name = "PIPELINE", + .socket_id = 0, + }; + uint32_t n; + struct rte_table_acl_rule_add_params rule_params; + struct rte_pipeline_table_acl_rule_delete_params *delete_params; + parse_5tuple parser; + char acl_name[64]; + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", + __func__); + goto fail; + } + + /* Input port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .burst_size = BURST_SIZE, + }; + + /* Put in action for some ports */ + if (i) + port_params.f_action = port_in_action; + + ret = rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i]); + if (ret) { + rte_panic("Unable to configure input port %d, ret:%d\n", + i, ret); + goto fail; + } + } + + /* output Port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = rings_tx[i], + .tx_burst_sz = BURST_SIZE, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) { + rte_panic("Unable to configure output port %d\n", i); + goto fail; + } + } + + /* Table configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_params table_params; + + /* Set up defaults for stub */ + table_params.ops = &rte_table_stub_ops; + table_params.arg_create = NULL; + table_params.f_action_hit = action_handler_hit; + table_params.f_action_miss = NULL; + table_params.action_data_size = 0; + + RTE_LOG(INFO, PIPELINE, "miss_action=%x\n", + table_entry_miss_action); + + printf("RTE_ACL_RULE_SZ(%zu) = %zu\n", DIM(ipv4_defs), + RTE_ACL_RULE_SZ(DIM(ipv4_defs))); + + struct rte_table_acl_params acl_params; + + acl_params.n_rules = 1 << 5; + acl_params.n_rule_fields = DIM(ipv4_defs); + rte_snprintf(acl_name, sizeof(acl_name), "ACL%d", i); + acl_params.name = acl_name; + memcpy(acl_params.field_format, ipv4_defs, sizeof(ipv4_defs)); + + table_params.ops = &rte_table_acl_ops; + table_params.arg_create = &acl_params; + + if (rte_pipeline_table_create(p, &table_params, &table_id[i])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + + if (connect_miss_action_to_table) { + if (rte_pipeline_table_create(p, &table_params, + &table_id[i+2])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + } + } + + for (i = 0; i < N_PORTS; i++) { + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id[i])) { + rte_panic("Unable to connect input port %u to " + "table %u\n", + port_in_id[i], table_id[i]); + goto fail; + } + } + + /* Add entries to tables */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_entry table_entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i^1]}, + }; + int key_found; + struct rte_pipeline_table_entry *entry_ptr; + + memset(&rule_params, 0, sizeof(rule_params)); + parser = parse_cb_ipv4_rule; + + for (n = 1; n <= 5; n++) { + rte_snprintf(line, sizeof(line), "%s", lines[n-1]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &rule_params); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, + "line %u: parse_cb_ipv4vlan_rule" + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + + rule_params.priority = RTE_ACL_MAX_PRIORITY - n; + + ret = rte_pipeline_table_entry_add(p, table_id[i], + &rule_params, + &table_entry, &key_found, &entry_ptr); + if (ret < 0) { + rte_panic("Add entry to table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } + } + + /* delete a few rules */ + for (n = 2; n <= 3; n++) { + rte_snprintf(line, sizeof(line), "%s", lines[n-1]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &rule_params); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, "line %u: parse rule " + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + + delete_params = (struct + rte_pipeline_table_acl_rule_delete_params *) + &(rule_params.field_value[0]); + ret = rte_pipeline_table_entry_delete(p, table_id[i], + delete_params, &key_found, NULL); + if (ret < 0) { + rte_panic("Add entry to table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } else + printf("Deleted Rule.\n"); + } + + + /* Try to add duplicates */ + for (n = 1; n <= 5; n++) { + rte_snprintf(line, sizeof(line), "%s", lines[n-1]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &rule_params); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, "line %u: parse rule" + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + + rule_params.priority = RTE_ACL_MAX_PRIORITY - n; + + ret = rte_pipeline_table_entry_add(p, table_id[i], + &rule_params, + &table_entry, &key_found, &entry_ptr); + if (ret < 0) { + rte_panic("Add entry to table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } + } + } + + /* Enable input ports */ + for (i = 0; i < N_PORTS ; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) { + rte_panic("Pipeline consistency check failed\n"); + goto fail; + } + + return 0; +fail: + + return -1; +} + +static int +test_pipeline_single_filter(int expected_count) +{ + int i, j, ret, tx_count; + struct ipv4_5tuple five_tuple; + + /* Allocate a few mbufs and manually insert into the rings. */ + for (i = 0; i < N_PORTS; i++) { + for (j = 0; j < 8; j++) { + struct rte_mbuf *mbuf; + + mbuf = rte_pktmbuf_alloc(pool); + memset(mbuf->pkt.data, 0x00, + sizeof(struct ipv4_5tuple)); + + five_tuple.proto = j; + five_tuple.ip_src = rte_bswap32(IPv4(192, 168, j, 1)); + five_tuple.ip_dst = rte_bswap32(IPv4(10, 4, j, 1)); + five_tuple.port_src = rte_bswap16(100 + j); + five_tuple.port_dst = rte_bswap16(200 + j); + + memcpy(mbuf->pkt.data, &five_tuple, + sizeof(struct ipv4_5tuple)); + RTE_LOG(INFO, PIPELINE, "%s: Enqueue onto ring %d\n", + __func__, i); + rte_ring_enqueue(rings_rx[i], mbuf); + } + } + + /* Run pipeline once */ + rte_pipeline_run(p); + + rte_pipeline_flush(p); + + tx_count = 0; + + for (i = 0; i < N_PORTS; i++) { + void *objs[RING_TX_SIZE]; + struct rte_mbuf *mbuf; + + ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10); + if (ret <= 0) { + printf("Got no objects from ring %d - error code %d\n", + i, ret); + } else { + printf("Got %d object(s) from ring %d!\n", ret, i); + for (j = 0; j < ret; j++) { + mbuf = (struct rte_mbuf *)objs[j]; + rte_hexdump(stdout, "mbuf", mbuf->pkt.data, 64); + rte_pktmbuf_free(mbuf); + } + tx_count += ret; + } + } + + if (tx_count != expected_count) { + RTE_LOG(INFO, PIPELINE, + "%s: Unexpected packets for ACL test, " + "expected %d, got %d\n", + __func__, expected_count, tx_count); + goto fail; + } + + rte_pipeline_free(p); + + return 0; +fail: + return -1; + +} + +int +test_table_ACL(void) +{ + + + override_hit_mask = 0xFF; /* All packets are a hit */ + + setup_acl_pipeline(); + if (test_pipeline_single_filter(10) < 0) + return -1; + + return 0; +} + +#endif diff --git a/app/test/test_table_acl.h b/app/test/test_table_acl.h new file mode 100644 index 0000000000..f57cb27b41 --- /dev/null +++ b/app/test/test_table_acl.h @@ -0,0 +1,35 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +/* Test prototypes */ +int test_table_ACL(void); diff --git a/app/test/test_table_combined.c b/app/test/test_table_combined.c new file mode 100644 index 0000000000..3380ff11e8 --- /dev/null +++ b/app/test/test_table_combined.c @@ -0,0 +1,784 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +#ifdef RTE_LIBRTE_TABLE +#include +#include "test_table_combined.h" +#include "test_table.h" +#include + +#define MAX_TEST_KEYS 128 +#define N_PACKETS 50 + +enum check_table_result { + CHECK_TABLE_OK, + CHECK_TABLE_PORT_CONFIG, + CHECK_TABLE_PORT_ENABLE, + CHECK_TABLE_TABLE_CONFIG, + CHECK_TABLE_ENTRY_ADD, + CHECK_TABLE_DEFAULT_ENTRY_ADD, + CHECK_TABLE_CONNECT, + CHECK_TABLE_MANAGE_ERROR, + CHECK_TABLE_CONSISTENCY, + CHECK_TABLE_NO_TRAFFIC, + CHECK_TABLE_INVALID_PARAMETER, +}; + +struct table_packets { + uint32_t hit_packet[MAX_TEST_KEYS]; + uint32_t miss_packet[MAX_TEST_KEYS]; + uint32_t n_hit_packets; + uint32_t n_miss_packets; +}; + +combined_table_test table_tests_combined[] = { + test_table_lpm_combined, + test_table_lpm_ipv6_combined, + test_table_hash8lru, + test_table_hash8ext, + test_table_hash16lru, + test_table_hash16ext, + test_table_hash32lru, + test_table_hash32ext, +}; + +unsigned n_table_tests_combined = RTE_DIM(table_tests_combined); + +/* Generic port tester function */ +static int +test_table_type(struct rte_table_ops *table_ops, void *table_args, + void *key, struct table_packets *table_packets, + struct manage_ops *manage_ops, unsigned n_ops) +{ + uint32_t ring_in_id, table_id, ring_out_id, ring_out_2_id; + unsigned i; + + RTE_SET_USED(manage_ops); + RTE_SET_USED(n_ops); + /* Create pipeline */ + struct rte_pipeline_params pipeline_params = { + .name = "pipeline", + .socket_id = 0, + }; + + struct rte_pipeline *pipeline = rte_pipeline_create(&pipeline_params); + + /* Create input ring */ + struct rte_port_ring_reader_params ring_params_rx = { + .ring = RING_RX, + }; + + struct rte_port_ring_writer_params ring_params_tx = { + .ring = RING_RX, + .tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX, + }; + + struct rte_pipeline_port_in_params ring_in_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *)&ring_params_rx, + .f_action = NULL, + .burst_size = RTE_PORT_IN_BURST_SIZE_MAX, + }; + + if (rte_pipeline_port_in_create(pipeline, &ring_in_params, + &ring_in_id) != 0) + return -CHECK_TABLE_PORT_CONFIG; + + /* Create table */ + struct rte_pipeline_table_params table_params = { + .ops = table_ops, + .arg_create = table_args, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(pipeline, &table_params, &table_id) != 0) + return -CHECK_TABLE_TABLE_CONFIG; + + /* Create output ports */ + ring_params_tx.ring = RING_TX; + + struct rte_pipeline_port_out_params ring_out_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *)&ring_params_tx, + .f_action = NULL, + }; + + if (rte_pipeline_port_out_create(pipeline, &ring_out_params, + &ring_out_id) != 0) + return -CHECK_TABLE_PORT_CONFIG; + + ring_params_tx.ring = RING_TX_2; + + if (rte_pipeline_port_out_create(pipeline, &ring_out_params, + &ring_out_2_id) != 0) + return -CHECK_TABLE_PORT_CONFIG; + + /* Add entry to the table */ + struct rte_pipeline_table_entry default_entry = { + .action = RTE_PIPELINE_ACTION_DROP, + {.table_id = ring_out_id}, + }; + + struct rte_pipeline_table_entry table_entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.table_id = ring_out_id}, + }; + + struct rte_pipeline_table_entry *default_entry_ptr, *entry_ptr; + + int key_found; + + if (rte_pipeline_table_default_entry_add(pipeline, table_id, + &default_entry, &default_entry_ptr) != 0) + return -CHECK_TABLE_DEFAULT_ENTRY_ADD; + + if (rte_pipeline_table_entry_add(pipeline, table_id, + key ? key : &table_entry, &table_entry, &key_found, + &entry_ptr) != 0) + return -CHECK_TABLE_ENTRY_ADD; + + /* Create connections and check consistency */ + if (rte_pipeline_port_in_connect_to_table(pipeline, ring_in_id, + table_id) != 0) + return -CHECK_TABLE_CONNECT; + + if (rte_pipeline_port_in_enable(pipeline, ring_in_id) != 0) + return -CHECK_TABLE_PORT_ENABLE; + + if (rte_pipeline_check(pipeline) != 0) + return -CHECK_TABLE_CONSISTENCY; + + + + /* Flow test - All hits */ + if (table_packets->n_hit_packets) { + for (i = 0; i < table_packets->n_hit_packets; i++) + RING_ENQUEUE(RING_RX, table_packets->hit_packet[i]); + + RUN_PIPELINE(pipeline); + + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, + table_packets->n_hit_packets); + } + + /* Flow test - All misses */ + if (table_packets->n_miss_packets) { + for (i = 0; i < table_packets->n_miss_packets; i++) + RING_ENQUEUE(RING_RX, table_packets->miss_packet[i]); + + RUN_PIPELINE(pipeline); + + VERIFY_TRAFFIC(RING_TX, table_packets->n_miss_packets, 0); + } + + /* Flow test - Half hits, half misses */ + if (table_packets->n_hit_packets && table_packets->n_miss_packets) { + for (i = 0; i < (table_packets->n_hit_packets) / 2; i++) + RING_ENQUEUE(RING_RX, table_packets->hit_packet[i]); + + for (i = 0; i < (table_packets->n_miss_packets) / 2; i++) + RING_ENQUEUE(RING_RX, table_packets->miss_packet[i]); + + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, + table_packets->n_hit_packets / 2); + } + + /* Flow test - Single packet */ + if (table_packets->n_hit_packets) { + RING_ENQUEUE(RING_RX, table_packets->hit_packet[0]); + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, 1); + } + if (table_packets->n_miss_packets) { + RING_ENQUEUE(RING_RX, table_packets->miss_packet[0]); + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_miss_packets, 0); + } + + + /* Change table entry action */ + printf("Change entry action\n"); + table_entry.table_id = ring_out_2_id; + + if (rte_pipeline_table_default_entry_add(pipeline, table_id, + &default_entry, &default_entry_ptr) != 0) + return -CHECK_TABLE_ENTRY_ADD; + + if (rte_pipeline_table_entry_add(pipeline, table_id, + key ? key : &table_entry, &table_entry, &key_found, + &entry_ptr) != 0) + return -CHECK_TABLE_ENTRY_ADD; + + /* Check that traffic destination has changed */ + if (table_packets->n_hit_packets) { + for (i = 0; i < table_packets->n_hit_packets; i++) + RING_ENQUEUE(RING_RX, table_packets->hit_packet[i]); + + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, 0); + VERIFY_TRAFFIC(RING_TX_2, table_packets->n_hit_packets, + table_packets->n_hit_packets); + } + + printf("delete entry\n"); + /* Delete table entry */ + rte_pipeline_table_entry_delete(pipeline, table_id, + key ? key : &table_entry, &key_found, NULL); + + rte_pipeline_free(pipeline); + + return 0; +} + +/* Table tests */ +int +test_table_stub_combined(void) +{ + int status, i; + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < N_PACKETS; i++) + table_packets.hit_packet[i] = i; + + table_packets.n_hit_packets = N_PACKETS; + table_packets.n_miss_packets = 0; + + status = test_table_type(&rte_table_stub_ops, NULL, NULL, + &table_packets, NULL, 1); + VERIFY(status, CHECK_TABLE_OK); + + return 0; +} + +int +test_table_lpm_combined(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_lpm_params lpm_params = { + .n_rules = 1 << 16, + .entry_unique_size = 8, + .offset = 0, + }; + + struct rte_table_lpm_key lpm_key = { + .ip = 0xadadadad, + .depth = 16, + }; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + + for (i = 0; i < N_PACKETS; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < N_PACKETS; i++) + table_packets.miss_packet[i] = 0xfefefefe; + + table_packets.n_hit_packets = N_PACKETS; + table_packets.n_miss_packets = N_PACKETS; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + lpm_params.n_rules = 0; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + lpm_params.n_rules = 1 << 24; + lpm_key.depth = 0; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + lpm_key.depth = 33; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + return 0; +} + +int +test_table_lpm_ipv6_combined(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_lpm_ipv6_params lpm_ipv6_params = { + .n_rules = 1 << 16, + .number_tbl8s = 1 << 13, + .entry_unique_size = 8, + .offset = 32, + }; + + struct rte_table_lpm_ipv6_key lpm_ipv6_key = { + .depth = 16, + }; + memset(lpm_ipv6_key.ip, 0xad, 16); + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < N_PACKETS; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < N_PACKETS; i++) + table_packets.miss_packet[i] = 0xadadadab; + + table_packets.n_hit_packets = N_PACKETS; + table_packets.n_miss_packets = N_PACKETS; + + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + lpm_ipv6_params.n_rules = 0; + + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + lpm_ipv6_params.n_rules = 1 << 24; + lpm_ipv6_key.depth = 0; + + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + lpm_ipv6_key.depth = 129; + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + return 0; +} + +int +test_table_hash8lru(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key8_lru_params key8lru_params = { + .n_entries = 1<<24, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = 0, + .key_offset = 32, + }; + + uint8_t key8lru[8]; + uint32_t *k8lru = (uint32_t *) key8lru; + + memset(key8lru, 0, sizeof(key8lru)); + k8lru[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xfefefefe; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key8_lru_ops, + (void *)&key8lru_params, (void *)key8lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key8lru_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key8_lru_ops, + (void *)&key8lru_params, (void *)key8lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key8lru_params.n_entries = 1<<16; + key8lru_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key8_lru_ops, + (void *)&key8lru_params, (void *)key8lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash16lru(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key16_lru_params key16lru_params = { + .n_entries = 1<<16, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = 0, + .key_offset = 32, + }; + + uint8_t key16lru[16]; + uint32_t *k16lru = (uint32_t *) key16lru; + + memset(key16lru, 0, sizeof(key16lru)); + k16lru[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xfefefefe; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key16_lru_ops, + (void *)&key16lru_params, (void *)key16lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key16lru_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key16_lru_ops, + (void *)&key16lru_params, (void *)key16lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key16lru_params.n_entries = 1<<16; + key16lru_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key16_lru_ops, + (void *)&key16lru_params, (void *)key16lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash32lru(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key32_lru_params key32lru_params = { + .n_entries = 1<<16, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = 0, + .key_offset = 32, + }; + + uint8_t key32lru[32]; + uint32_t *k32lru = (uint32_t *) key32lru; + + memset(key32lru, 0, sizeof(key32lru)); + k32lru[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key32_lru_ops, + (void *)&key32lru_params, (void *)key32lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key32lru_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key32_lru_ops, + (void *)&key32lru_params, (void *)key32lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key32lru_params.n_entries = 1<<16; + key32lru_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key32_lru_ops, + (void *)&key32lru_params, (void *)key32lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash8ext(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key8_ext_params key8ext_params = { + .n_entries = 1<<16, + .n_entries_ext = 1<<15, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = 0, + .key_offset = 32, + }; + + uint8_t key8ext[8]; + uint32_t *k8ext = (uint32_t *) key8ext; + + memset(key8ext, 0, sizeof(key8ext)); + k8ext[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key8ext_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key8ext_params.n_entries = 1<<16; + key8ext_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key8ext_params.f_hash = pipeline_test_hash; + key8ext_params.n_entries_ext = 0; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash16ext(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key16_ext_params key16ext_params = { + .n_entries = 1<<16, + .n_entries_ext = 1<<15, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = 0, + .key_offset = 32, + }; + + uint8_t key16ext[16]; + uint32_t *k16ext = (uint32_t *) key16ext; + + memset(key16ext, 0, sizeof(key16ext)); + k16ext[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key16ext_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key16ext_params.n_entries = 1<<16; + key16ext_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key16ext_params.f_hash = pipeline_test_hash; + key16ext_params.n_entries_ext = 0; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash32ext(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key32_ext_params key32ext_params = { + .n_entries = 1<<16, + .n_entries_ext = 1<<15, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = 0, + .key_offset = 32, + }; + + uint8_t key32ext[32]; + uint32_t *k32ext = (uint32_t *) key32ext; + + memset(key32ext, 0, sizeof(key32ext)); + k32ext[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key32ext_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key32ext_params.n_entries = 1<<16; + key32ext_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key32ext_params.f_hash = pipeline_test_hash; + key32ext_params.n_entries_ext = 0; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +#endif diff --git a/app/test/test_table_combined.h b/app/test/test_table_combined.h new file mode 100644 index 0000000000..f94f09ffef --- /dev/null +++ b/app/test/test_table_combined.h @@ -0,0 +1,55 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +/* Test prototypes */ +int test_table_stub_combined(void); +int test_table_lpm_combined(void); +int test_table_lpm_ipv6_combined(void); +#ifdef RTE_LIBRTE_ACL +int test_table_acl(void); +#endif +int test_table_hash8unoptimized(void); +int test_table_hash8lru(void); +int test_table_hash8ext(void); +int test_table_hash16unoptimized(void); +int test_table_hash16lru(void); +int test_table_hash16ext(void); +int test_table_hash32unoptimized(void); +int test_table_hash32lru(void); +int test_table_hash32ext(void); + +/* Extern variables */ +typedef int (*combined_table_test)(void); + +extern combined_table_test table_tests_combined[]; +extern unsigned n_table_tests_combined; diff --git a/app/test/test_table_pipeline.c b/app/test/test_table_pipeline.c new file mode 100644 index 0000000000..35644a646d --- /dev/null +++ b/app/test/test_table_pipeline.c @@ -0,0 +1,603 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +#ifndef RTE_LIBRTE_PIPELINE + +#include "test.h" + +#else + +#include +#include +#include +#include +#include +#include "test_table.h" +#include "test_table_pipeline.h" + +#define RTE_CBUF_UINT8_PTR(cbuf, offset) \ + (&cbuf->data[offset]) +#define RTE_CBUF_UINT32_PTR(cbuf, offset) \ + (&cbuf->data32[offset/sizeof(uint32_t)]) + +#if 0 + +static rte_pipeline_port_out_action_handler port_action_0x00 + (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); +static rte_pipeline_port_out_action_handler port_action_0xFF + (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); +static rte_pipeline_port_out_action_handler port_action_stub + (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); + + +rte_pipeline_port_out_action_handler port_action_0x00(struct rte_mbuf **pkts, + uint32_t n, + uint64_t *pkts_mask, + void *arg) +{ + RTE_SET_USED(pkts); + RTE_SET_USED(n); + RTE_SET_USED(arg); + printf("Port Action 0x00\n"); + *pkts_mask = 0x00; + return 0; +} + +rte_pipeline_port_out_action_handler port_action_0xFF(struct rte_mbuf **pkts, + uint32_t n, + uint64_t *pkts_mask, + void *arg) +{ + RTE_SET_USED(pkts); + RTE_SET_USED(n); + RTE_SET_USED(arg); + printf("Port Action 0xFF\n"); + *pkts_mask = 0xFF; + return 0; +} + +rte_pipeline_port_out_action_handler port_action_stub(struct rte_mbuf **pkts, + uint32_t n, + uint64_t *pkts_mask, + void *arg) +{ + RTE_SET_USED(pkts); + RTE_SET_USED(n); + RTE_SET_USED(pkts_mask); + RTE_SET_USED(arg); + printf("Port Action stub\n"); + return 0; +} + +#endif + +rte_pipeline_table_action_handler_hit +table_action_0x00(struct rte_mbuf **pkts, uint64_t *pkts_mask, + struct rte_pipeline_table_entry **actions, uint32_t action_mask); + +rte_pipeline_table_action_handler_hit +table_action_stub_hit(struct rte_mbuf **pkts, uint64_t *pkts_mask, + struct rte_pipeline_table_entry **actions, uint32_t action_mask); + +rte_pipeline_table_action_handler_miss +table_action_stub_miss(struct rte_mbuf **pkts, uint64_t *pkts_mask, + struct rte_pipeline_table_entry *action, uint32_t action_mask); + +rte_pipeline_table_action_handler_hit +table_action_0x00(__attribute__((unused)) struct rte_mbuf **pkts, + uint64_t *pkts_mask, + __attribute__((unused)) struct rte_pipeline_table_entry **actions, + __attribute__((unused)) uint32_t action_mask) +{ + printf("Table Action, setting pkts_mask to 0x00\n"); + *pkts_mask = 0x00; + return 0; +} + +rte_pipeline_table_action_handler_hit +table_action_stub_hit(__attribute__((unused)) struct rte_mbuf **pkts, + uint64_t *pkts_mask, + __attribute__((unused)) struct rte_pipeline_table_entry **actions, + __attribute__((unused)) uint32_t action_mask) +{ + printf("STUB Table Action Hit - doing nothing\n"); + printf("STUB Table Action Hit - setting mask to 0x%"PRIx64"\n", + override_hit_mask); + *pkts_mask = override_hit_mask; + return 0; +} +rte_pipeline_table_action_handler_miss +table_action_stub_miss(__attribute__((unused)) struct rte_mbuf **pkts, + uint64_t *pkts_mask, + __attribute__((unused)) struct rte_pipeline_table_entry *action, + __attribute__((unused)) uint32_t action_mask) +{ + printf("STUB Table Action Miss - setting mask to 0x%"PRIx64"\n", + override_miss_mask); + *pkts_mask = override_miss_mask; + return 0; +} + + +enum e_test_type { + e_TEST_STUB = 0, + e_TEST_LPM, + e_TEST_LPM6, + e_TEST_HASH_LRU_8, + e_TEST_HASH_LRU_16, + e_TEST_HASH_LRU_32, + e_TEST_HASH_EXT_8, + e_TEST_HASH_EXT_16, + e_TEST_HASH_EXT_32 +}; + +char pipeline_test_names[][64] = { + "Stub", + "LPM", + "LPMv6", + "8-bit LRU Hash", + "16-bit LRU Hash", + "32-bit LRU Hash", + "16-bit Ext Hash", + "8-bit Ext Hash", + "32-bit Ext Hash", + "" +}; + + +static int +cleanup_pipeline(void) +{ + + rte_pipeline_free(p); + + return 0; +} + + +static int check_pipeline_invalid_params(void); + +static int +check_pipeline_invalid_params(void) +{ + struct rte_pipeline_params pipeline_params_1 = { + .name = NULL, + .socket_id = 0, + }; + struct rte_pipeline_params pipeline_params_2 = { + .name = "PIPELINE", + .socket_id = -1, + }; + struct rte_pipeline_params pipeline_params_3 = { + .name = "PIPELINE", + .socket_id = 127, + }; + + p = rte_pipeline_create(NULL); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, + "%s: configured pipeline with null params\n", + __func__); + goto fail; + } + p = rte_pipeline_create(&pipeline_params_1); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with NULL " + "name\n", __func__); + goto fail; + } + + p = rte_pipeline_create(&pipeline_params_2); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid " + "socket\n", __func__); + goto fail; + } + + p = rte_pipeline_create(&pipeline_params_3); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid " + "socket\n", __func__); + goto fail; + } + + /* Check pipeline consistency */ + if (!rte_pipeline_check(p)) { + rte_panic("Pipeline consistency reported as OK\n"); + goto fail; + } + + + return 0; +fail: + return -1; +} + + +static int +setup_pipeline(int test_type) +{ + int ret; + int i; + struct rte_pipeline_params pipeline_params = { + .name = "PIPELINE", + .socket_id = 0, + }; + + RTE_LOG(INFO, PIPELINE, "%s: **** Setting up %s test\n", + __func__, pipeline_test_names[test_type]); + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", + __func__); + goto fail; + } + + ret = rte_pipeline_free(p); + if (ret != 0) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to free pipeline\n", + __func__); + goto fail; + } + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", + __func__); + goto fail; + } + + + /* Input port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .burst_size = BURST_SIZE, + }; + + /* Put in action for some ports */ + if (i) + port_params.f_action = NULL; + + ret = rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i]); + if (ret) { + rte_panic("Unable to configure input port %d, ret:%d\n", + i, ret); + goto fail; + } + } + + /* output Port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = rings_tx[i], + .tx_burst_sz = BURST_SIZE, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + if (i) + port_params.f_action = port_out_action; + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) { + rte_panic("Unable to configure output port %d\n", i); + goto fail; + } + } + + /* Table configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_stub_ops, + .arg_create = NULL, + .f_action_hit = action_handler_hit, + .f_action_miss = action_handler_miss, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id[i])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + + if (connect_miss_action_to_table) + if (rte_pipeline_table_create(p, &table_params, + &table_id[i+2])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + } + + for (i = 0; i < N_PORTS; i++) + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id[i])) { + rte_panic("Unable to connect input port %u to " + "table %u\n", port_in_id[i], table_id[i]); + goto fail; + } + + /* Add entries to tables */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_entry default_entry = { + .action = (enum rte_pipeline_action) + table_entry_default_action, + {.port_id = port_out_id[i^1]}, + }; + struct rte_pipeline_table_entry *default_entry_ptr; + + if (connect_miss_action_to_table) { + printf("Setting first table to output to next table\n"); + default_entry.action = RTE_PIPELINE_ACTION_TABLE; + default_entry.table_id = table_id[i+2]; + } + + /* Add the default action for the table. */ + ret = rte_pipeline_table_default_entry_add(p, table_id[i], + &default_entry, &default_entry_ptr); + if (ret < 0) { + rte_panic("Unable to add default entry to table %u " + "code %d\n", table_id[i], ret); + goto fail; + } else + printf("Added default entry to table id %d with " + "action %x\n", + table_id[i], default_entry.action); + + if (connect_miss_action_to_table) { + /* We create a second table so the first can pass + traffic into it */ + struct rte_pipeline_table_entry default_entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i^1]}, + }; + printf("Setting secont table to output to port\n"); + + /* Add the default action for the table. */ + ret = rte_pipeline_table_default_entry_add(p, + table_id[i+2], + &default_entry, &default_entry_ptr); + if (ret < 0) { + rte_panic("Unable to add default entry to " + "table %u code %d\n", + table_id[i], ret); + goto fail; + } else + printf("Added default entry to table id %d " + "with action %x\n", + table_id[i], default_entry.action); + } + } + + /* Enable input ports */ + for (i = 0; i < N_PORTS ; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) { + rte_panic("Pipeline consistency check failed\n"); + goto fail; + } else + printf("Pipeline Consistency OK!\n"); + + return 0; +fail: + + return -1; +} + +static int +test_pipeline_single_filter(int test_type, int expected_count) +{ + int i; + int j; + int ret; + int tx_count; + + RTE_LOG(INFO, PIPELINE, "%s: **** Running %s test\n", + __func__, pipeline_test_names[test_type]); + /* Run pipeline once */ + rte_pipeline_run(p); + + + ret = rte_pipeline_flush(NULL); + if (ret != -EINVAL) { + RTE_LOG(INFO, PIPELINE, + "%s: No pipeline flush error NULL pipeline (%d)\n", + __func__, ret); + goto fail; + } + + /* + * Allocate a few mbufs and manually insert into the rings. */ + for (i = 0; i < N_PORTS; i++) + for (j = 0; j < N_PORTS; j++) { + struct rte_mbuf *m; + uint8_t *key; + uint32_t *k32; + + m = rte_pktmbuf_alloc(pool); + if (m == NULL) { + rte_panic("Failed to alloc mbuf from pool\n"); + return -1; + } + key = RTE_MBUF_METADATA_UINT8_PTR(m, 32); + + k32 = (uint32_t *) key; + k32[0] = 0xadadadad >> (j % 2); + + RTE_LOG(INFO, PIPELINE, "%s: Enqueue onto ring %d\n", + __func__, i); + rte_ring_enqueue(rings_rx[i], m); + } + + /* Run pipeline once */ + rte_pipeline_run(p); + + /* + * need to flush the pipeline, as there may be less hits than the burst + size and they will not have been flushed to the tx rings. */ + rte_pipeline_flush(p); + + /* + * Now we'll see what we got back on the tx rings. We should see whatever + * packets we had hits on that were destined for the output ports. + */ + tx_count = 0; + + for (i = 0; i < N_PORTS; i++) { + void *objs[RING_TX_SIZE]; + struct rte_mbuf *mbuf; + + ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10); + if (ret <= 0) + printf("Got no objects from ring %d - error code %d\n", + i, ret); + else { + printf("Got %d object(s) from ring %d!\n", ret, i); + for (j = 0; j < ret; j++) { + mbuf = (struct rte_mbuf *)objs[j]; + rte_hexdump(stdout, "Object:", mbuf->pkt.data, + mbuf->pkt.data_len); + rte_pktmbuf_free(mbuf); + } + tx_count += ret; + } + } + + if (tx_count != expected_count) { + RTE_LOG(INFO, PIPELINE, + "%s: Unexpected packets out for %s test, expected %d, " + "got %d\n", __func__, pipeline_test_names[test_type], + expected_count, tx_count); + goto fail; + } + + cleanup_pipeline(); + + return 0; +fail: + return -1; + +} + +int +test_table_pipeline(void) +{ + /* TEST - All packets dropped */ + action_handler_hit = NULL; + action_handler_miss = NULL; + table_entry_default_action = RTE_PIPELINE_ACTION_DROP; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 0) < 0) + return -1; + + /* TEST - All packets passed through */ + table_entry_default_action = RTE_PIPELINE_ACTION_PORT; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) + return -1; + + /* TEST - one packet per port */ + action_handler_hit = NULL; + action_handler_miss = + (rte_pipeline_table_action_handler_miss) table_action_stub_miss; + table_entry_default_action = RTE_PIPELINE_ACTION_PORT; + override_miss_mask = 0x01; /* one packet per port */ + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) + return -1; + + /* TEST - one packet per port */ + override_miss_mask = 0x02; /*all per port */ + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) + return -1; + + /* TEST - all packets per port */ + override_miss_mask = 0x03; /*all per port */ + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) + return -1; + + /* + * This test will set up two tables in the pipeline. the first table + * will forward to another table on miss, and the second table will + * forward to port. + */ + connect_miss_action_to_table = 1; + table_entry_default_action = RTE_PIPELINE_ACTION_TABLE; + action_handler_hit = NULL; /* not for stub, hitmask always zero */ + action_handler_miss = NULL; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) + return -1; + connect_miss_action_to_table = 0; + + printf("TEST - two tables, hitmask override to 0x01\n"); + connect_miss_action_to_table = 1; + action_handler_miss = + (rte_pipeline_table_action_handler_miss)table_action_stub_miss; + override_miss_mask = 0x01; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) + return -1; + connect_miss_action_to_table = 0; + + if (check_pipeline_invalid_params()) { + RTE_LOG(INFO, PIPELINE, "%s: Check pipeline invalid params " + "failed.\n", __func__); + return -1; + } + + return 0; +} + +#endif diff --git a/app/test/test_table_pipeline.h b/app/test/test_table_pipeline.h new file mode 100644 index 0000000000..b3f20ba38e --- /dev/null +++ b/app/test/test_table_pipeline.h @@ -0,0 +1,35 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +/* Test prototypes */ +int test_table_pipeline(void); diff --git a/app/test/test_table_ports.c b/app/test/test_table_ports.c new file mode 100644 index 0000000000..e9d45b0e90 --- /dev/null +++ b/app/test/test_table_ports.c @@ -0,0 +1,224 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +#ifdef RTE_LIBRTE_TABLE + +#include "test_table_ports.h" +#include "test_table.h" + +port_test port_tests[] = { + test_port_ring_reader, + test_port_ring_writer, +}; + +unsigned n_port_tests = RTE_DIM(port_tests); + +/* Port tests */ +int +test_port_ring_reader(void) +{ + int status, i; + struct rte_port_ring_reader_params port_ring_reader_params; + void *port; + + /* Invalid params */ + port = rte_port_ring_reader_ops.f_create(NULL, 0); + if (port != NULL) + return -1; + + status = rte_port_ring_reader_ops.f_free(port); + if (status >= 0) + return -2; + + /* Create and free */ + port_ring_reader_params.ring = RING_RX; + port = rte_port_ring_reader_ops.f_create(&port_ring_reader_params, 0); + if (port == NULL) + return -3; + + status = rte_port_ring_reader_ops.f_free(port); + if (status != 0) + return -4; + + /* -- Traffic RX -- */ + int expected_pkts, received_pkts; + struct rte_mbuf *res_mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + void *mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + + port_ring_reader_params.ring = RING_RX; + port = rte_port_ring_reader_ops.f_create(&port_ring_reader_params, 0); + + /* Single packet */ + mbuf[0] = (void *)rte_pktmbuf_alloc(pool); + + expected_pkts = rte_ring_sp_enqueue_burst(port_ring_reader_params.ring, + mbuf, 1); + received_pkts = rte_port_ring_reader_ops.f_rx(port, res_mbuf, 1); + + if (received_pkts < expected_pkts) + return -5; + + rte_pktmbuf_free(res_mbuf[0]); + + /* Multiple packets */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + mbuf[i] = rte_pktmbuf_alloc(pool); + + expected_pkts = rte_ring_sp_enqueue_burst(port_ring_reader_params.ring, + (void * const *) mbuf, RTE_PORT_IN_BURST_SIZE_MAX); + received_pkts = rte_port_ring_reader_ops.f_rx(port, res_mbuf, + RTE_PORT_IN_BURST_SIZE_MAX); + + if (received_pkts < expected_pkts) + return -6; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + return 0; +} + +int +test_port_ring_writer(void) +{ + int status, i; + struct rte_port_ring_writer_params port_ring_writer_params; + void *port; + + /* Invalid params */ + port = rte_port_ring_writer_ops.f_create(NULL, 0); + if (port != NULL) + return -1; + + status = rte_port_ring_writer_ops.f_free(port); + if (status >= 0) + return -2; + + port_ring_writer_params.ring = NULL; + + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + if (port != NULL) + return -3; + + port_ring_writer_params.ring = RING_TX; + port_ring_writer_params.tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX + 1; + + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + if (port != NULL) + return -4; + + /* Create and free */ + port_ring_writer_params.ring = RING_TX; + port_ring_writer_params.tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX; + + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + if (port == NULL) + return -5; + + status = rte_port_ring_writer_ops.f_free(port); + if (status != 0) + return -6; + + /* -- Traffic TX -- */ + int expected_pkts, received_pkts; + struct rte_mbuf *mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + struct rte_mbuf *res_mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + + port_ring_writer_params.ring = RING_TX; + port_ring_writer_params.tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX; + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + + /* Single packet */ + mbuf[0] = rte_pktmbuf_alloc(pool); + + rte_port_ring_writer_ops.f_tx(port, mbuf[0]); + rte_port_ring_writer_ops.f_flush(port); + expected_pkts = 1; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz); + + if (received_pkts < expected_pkts) + return -7; + + rte_pktmbuf_free(res_mbuf[0]); + + /* Multiple packets */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) { + mbuf[i] = rte_pktmbuf_alloc(pool); + rte_port_ring_writer_ops.f_tx(port, mbuf[i]); + } + + expected_pkts = RTE_PORT_IN_BURST_SIZE_MAX; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz); + + if (received_pkts < expected_pkts) + return -8; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + /* TX Bulk */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + mbuf[i] = rte_pktmbuf_alloc(pool); + rte_port_ring_writer_ops.f_tx_bulk(port, mbuf, (uint64_t)-1); + + expected_pkts = RTE_PORT_IN_BURST_SIZE_MAX; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz); + + if (received_pkts < expected_pkts) + return -8; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + mbuf[i] = rte_pktmbuf_alloc(pool); + rte_port_ring_writer_ops.f_tx_bulk(port, mbuf, (uint64_t)-3); + rte_port_ring_writer_ops.f_tx_bulk(port, mbuf, (uint64_t)2); + + expected_pkts = RTE_PORT_IN_BURST_SIZE_MAX; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz); + + if (received_pkts < expected_pkts) + return -9; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + return 0; +} + +#endif diff --git a/app/test/test_table_ports.h b/app/test/test_table_ports.h new file mode 100644 index 0000000000..512b77fe4d --- /dev/null +++ b/app/test/test_table_ports.h @@ -0,0 +1,42 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +/* Test prototypes */ +int test_port_ring_reader(void); +int test_port_ring_writer(void); + +/* Extern variables */ +typedef int (*port_test)(void); + +extern port_test port_tests[]; +extern unsigned n_port_tests; diff --git a/app/test/test_table_tables.c b/app/test/test_table_tables.c new file mode 100644 index 0000000000..da8338cf89 --- /dev/null +++ b/app/test/test_table_tables.c @@ -0,0 +1,907 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +#ifdef RTE_LIBRTE_TABLE + +#include +#include +#include +#include +#include +#include "test_table_tables.h" +#include "test_table.h" + +table_test table_tests[] = { + test_table_stub, + test_table_array, + test_table_lpm, + test_table_lpm_ipv6, + test_table_hash_lru, + test_table_hash_ext, +}; + +#define PREPARE_PACKET(mbuf, value) do { \ + uint32_t *k32, *signature; \ + uint8_t *key; \ + mbuf = rte_pktmbuf_alloc(pool); \ + signature = RTE_MBUF_METADATA_UINT32_PTR(mbuf, 0); \ + key = RTE_MBUF_METADATA_UINT8_PTR(mbuf, 32); \ + memset(key, 0, 32); \ + k32 = (uint32_t *) key; \ + k32[0] = (value); \ + *signature = pipeline_test_hash(key, 0, 0); \ +} while (0) + +unsigned n_table_tests = RTE_DIM(table_tests); + +/* Function prototypes */ +static int +test_table_hash_lru_generic(struct rte_table_ops *ops); +static int +test_table_hash_ext_generic(struct rte_table_ops *ops); + +struct rte_bucket_4_8 { + /* Cache line 0 */ + uint64_t signature; + uint64_t lru_list; + struct rte_bucket_4_8 *next; + uint64_t next_valid; + uint64_t key[4]; + /* Cache line 1 */ + uint8_t data[0]; +}; + +#if RTE_TABLE_HASH_LRU_STRATEGY == 3 +uint64_t shuffles = 0xfffffffdfffbfff9ULL; +#else +uint64_t shuffles = 0x0003000200010000ULL; +#endif + +static int test_lru_update(void) +{ + struct rte_bucket_4_8 b; + struct rte_bucket_4_8 *bucket; + uint32_t i; + uint64_t pos; + uint64_t iterations; + uint64_t j; + int poss; + + printf("---------------------------\n"); + printf("Testing lru_update macro...\n"); + printf("---------------------------\n"); + bucket = &b; + iterations = 10; +#if RTE_TABLE_HASH_LRU_STRATEGY == 3 + bucket->lru_list = 0xFFFFFFFFFFFFFFFFULL; +#else + bucket->lru_list = 0x0000000100020003ULL; +#endif + poss = 0; + for (j = 0; j < iterations; j++) + for (i = 0; i < 9; i++) { + uint32_t idx = i >> 1; + lru_update(bucket, idx); + pos = lru_pos(bucket); + poss += pos; + printf("%s: %d lru_list=%016"PRIx64", upd=%d, " + "pos=%"PRIx64"\n", + __func__, i, bucket->lru_list, i>>1, pos); + } + + if (bucket->lru_list != shuffles) { + printf("%s: ERROR: %d lru_list=%016"PRIx64", expected %016" + PRIx64"\n", + __func__, i, bucket->lru_list, shuffles); + return -1; + } + printf("%s: output checksum of results =%d\n", + __func__, poss); +#if 0 + if (poss != 126) { + printf("%s: ERROR output checksum of results =%d expected %d\n", + __func__, poss, 126); + return -1; + } +#endif + + fflush(stdout); + + uint64_t sc_start = rte_rdtsc(); + iterations = 100000000; + poss = 0; + for (j = 0; j < iterations; j++) { + for (i = 0; i < 4; i++) { + lru_update(bucket, i); + pos |= bucket->lru_list; + } + } + uint64_t sc_end = rte_rdtsc(); + + printf("%s: output checksum of results =%llu\n", + __func__, (long long unsigned int)pos); + printf("%s: start=%016"PRIx64", end=%016"PRIx64"\n", + __func__, sc_start, sc_end); + printf("\nlru_update: %lu cycles per loop iteration.\n\n", + (long unsigned int)((sc_end-sc_start)/(iterations*4))); + + return 0; +} + +/* Table tests */ +int +test_table_stub(void) +{ + int i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + + /* Create */ + table = rte_table_stub_ops.f_create(NULL, 0, 1); + if (table == NULL) + return -1; + + /* Traffic flow */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) + PREPARE_PACKET(mbufs[i], 0xadadadad); + else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + expected_mask = 0; + rte_table_stub_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -2; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + return 0; +} + +int +test_table_array(void) +{ + int status, i; + uint64_t result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry1, entry2; + void *entry_ptr; + int key_found; + + /* Create */ + struct rte_table_array_params array_params; + + table = rte_table_array_ops.f_create(NULL, 0, 1); + if (table != NULL) + return -1; + + array_params.n_entries = 0; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table != NULL) + return -2; + + array_params.n_entries = 7; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table != NULL) + return -3; + + array_params.n_entries = 1 << 24; + array_params.offset = 1; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table != NULL) + return -4; + + array_params.offset = 32; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table == NULL) + return -5; + + /* Free */ + status = rte_table_array_ops.f_free(table); + if (status < 0) + return -6; + + status = rte_table_array_ops.f_free(NULL); + if (status == 0) + return -7; + + /* Add */ + struct rte_table_array_key array_key_1 = { + .pos = 10, + }; + struct rte_table_array_key array_key_2 = { + .pos = 20, + }; + entry1 = 'A'; + entry2 = 'B'; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table == NULL) + return -8; + + status = rte_table_array_ops.f_add(NULL, (void *) &array_key_1, &entry1, + &key_found, &entry_ptr); + if (status == 0) + return -9; + + status = rte_table_array_ops.f_add(table, (void *) &array_key_1, NULL, + &key_found, &entry_ptr); + if (status == 0) + return -10; + + status = rte_table_array_ops.f_add(table, (void *) &array_key_1, + &entry1, &key_found, &entry_ptr); + if (status != 0) + return -11; + + /* Traffic flow */ + status = rte_table_array_ops.f_add(table, (void *) &array_key_2, + &entry2, &key_found, &entry_ptr); + if (status != 0) + return -12; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) + PREPARE_PACKET(mbufs[i], 10); + else + PREPARE_PACKET(mbufs[i], 20); + + rte_table_array_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0 && *entries[i] != 'A') + return -13; + else + if (i % 2 == 1 && *entries[i] != 'B') + return -13; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = rte_table_array_ops.f_free(table); + + return 0; +} + +int +test_table_lpm(void) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + void *entry_ptr; + int key_found; + uint32_t entry_size = 1; + + /* Create */ + struct rte_table_lpm_params lpm_params; + + table = rte_table_lpm_ops.f_create(NULL, 0, entry_size); + if (table != NULL) + return -1; + + lpm_params.n_rules = 0; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -2; + + lpm_params.n_rules = 1 << 24; + lpm_params.offset = 1; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -3; + + lpm_params.offset = 32; + lpm_params.entry_unique_size = 0; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -4; + + lpm_params.entry_unique_size = entry_size + 1; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -5; + + lpm_params.entry_unique_size = entry_size; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table == NULL) + return -6; + + /* Free */ + status = rte_table_lpm_ops.f_free(table); + if (status < 0) + return -7; + + status = rte_table_lpm_ops.f_free(NULL); + if (status == 0) + return -8; + + /* Add */ + struct rte_table_lpm_key lpm_key; + lpm_key.ip = 0xadadadad; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, 1); + if (table == NULL) + return -9; + + status = rte_table_lpm_ops.f_add(NULL, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -10; + + status = rte_table_lpm_ops.f_add(table, NULL, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -11; + + status = rte_table_lpm_ops.f_add(table, &lpm_key, NULL, &key_found, + &entry_ptr); + if (status == 0) + return -12; + + lpm_key.depth = 0; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -13; + + lpm_key.depth = 33; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -14; + + lpm_key.depth = 16; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status != 0) + return -15; + + /* Delete */ + status = rte_table_lpm_ops.f_delete(NULL, &lpm_key, &key_found, NULL); + if (status == 0) + return -16; + + status = rte_table_lpm_ops.f_delete(table, NULL, &key_found, NULL); + if (status == 0) + return -17; + + lpm_key.depth = 0; + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status == 0) + return -18; + + lpm_key.depth = 33; + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status == 0) + return -19; + + lpm_key.depth = 16; + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status != 0) + return -20; + + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status != 0) + return -21; + + /* Traffic flow */ + entry = 'A'; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status < 0) + return -22; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + rte_table_lpm_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -21; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = rte_table_lpm_ops.f_free(table); + + return 0; +} + +int +test_table_lpm_ipv6(void) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + void *entry_ptr; + int key_found; + uint32_t entry_size = 1; + + /* Create */ + struct rte_table_lpm_ipv6_params lpm_params; + + table = rte_table_lpm_ipv6_ops.f_create(NULL, 0, entry_size); + if (table != NULL) + return -1; + + lpm_params.n_rules = 0; + + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -2; + + lpm_params.n_rules = 1 << 24; + lpm_params.number_tbl8s = 0; + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -2; + + lpm_params.number_tbl8s = 1 << 21; + lpm_params.entry_unique_size = 0; + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -2; + + lpm_params.entry_unique_size = entry_size + 1; + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -2; + + lpm_params.entry_unique_size = entry_size; + lpm_params.offset = 32; + + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table == NULL) + return -3; + + /* Free */ + status = rte_table_lpm_ipv6_ops.f_free(table); + if (status < 0) + return -4; + + status = rte_table_lpm_ipv6_ops.f_free(NULL); + if (status == 0) + return -5; + + /* Add */ + struct rte_table_lpm_ipv6_key lpm_key; + + lpm_key.ip[0] = 0xad; + lpm_key.ip[1] = 0xad; + lpm_key.ip[2] = 0xad; + lpm_key.ip[3] = 0xad; + + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table == NULL) + return -6; + + status = rte_table_lpm_ipv6_ops.f_add(NULL, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status == 0) + return -7; + + status = rte_table_lpm_ipv6_ops.f_add(table, NULL, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -8; + + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, NULL, &key_found, + &entry_ptr); + if (status == 0) + return -9; + + lpm_key.depth = 0; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status == 0) + return -10; + + lpm_key.depth = 129; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status == 0) + return -11; + + lpm_key.depth = 16; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status != 0) + return -12; + + /* Delete */ + status = rte_table_lpm_ipv6_ops.f_delete(NULL, &lpm_key, &key_found, + NULL); + if (status == 0) + return -13; + + status = rte_table_lpm_ipv6_ops.f_delete(table, NULL, &key_found, NULL); + if (status == 0) + return -14; + + lpm_key.depth = 0; + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status == 0) + return -15; + + lpm_key.depth = 129; + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status == 0) + return -16; + + lpm_key.depth = 16; + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status != 0) + return -17; + + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status != 0) + return -18; + + /* Traffic flow */ + entry = 'A'; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status < 0) + return -19; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + rte_table_lpm_ipv6_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -20; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = rte_table_lpm_ipv6_ops.f_free(table); + + return 0; +} + +static int +test_table_hash_lru_generic(struct rte_table_ops *ops) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + void *entry_ptr; + int key_found; + + /* Create */ + struct rte_table_hash_key8_lru_params hash_params; + + hash_params.n_entries = 0; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -1; + + hash_params.n_entries = 1 << 10; + hash_params.signature_offset = 1; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -2; + + hash_params.signature_offset = 0; + hash_params.key_offset = 1; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -3; + + hash_params.key_offset = 32; + hash_params.f_hash = NULL; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -4; + + hash_params.f_hash = pipeline_test_hash; + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -5; + + /* Free */ + status = ops->f_free(table); + if (status < 0) + return -6; + + status = ops->f_free(NULL); + if (status == 0) + return -7; + + /* Add */ + uint8_t key[32]; + uint32_t *k32 = (uint32_t *) &key; + + memset(key, 0, 32); + k32[0] = rte_be_to_cpu_32(0xadadadad); + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -8; + + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status != 0) + return -9; + + /* Delete */ + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -10; + + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -11; + + /* Traffic flow */ + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status < 0) + return -12; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + ops->f_lookup(table, mbufs, -1, &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -13; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = ops->f_free(table); + + return 0; +} + +static int +test_table_hash_ext_generic(struct rte_table_ops *ops) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + int key_found; + void *entry_ptr; + + /* Create */ + struct rte_table_hash_key8_ext_params hash_params; + + hash_params.n_entries = 0; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -1; + + hash_params.n_entries = 1 << 10; + hash_params.n_entries_ext = 0; + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -2; + + hash_params.n_entries_ext = 1 << 4; + hash_params.signature_offset = 1; + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -2; + + hash_params.signature_offset = 0; + hash_params.key_offset = 1; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -3; + + hash_params.key_offset = 32; + hash_params.f_hash = NULL; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -4; + + hash_params.f_hash = pipeline_test_hash; + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -5; + + /* Free */ + status = ops->f_free(table); + if (status < 0) + return -6; + + status = ops->f_free(NULL); + if (status == 0) + return -7; + + /* Add */ + uint8_t key[32]; + uint32_t *k32 = (uint32_t *) &key; + + memset(key, 0, 32); + k32[0] = rte_be_to_cpu_32(0xadadadad); + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -8; + + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status != 0) + return -9; + + /* Delete */ + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -10; + + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -11; + + /* Traffic flow */ + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status < 0) + return -12; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + ops->f_lookup(table, mbufs, -1, &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -13; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = ops->f_free(table); + + return 0; +} + +int +test_table_hash_lru(void) +{ + int status; + + status = test_table_hash_lru_generic(&rte_table_hash_key8_lru_ops); + if (status < 0) + return status; + + status = test_table_hash_lru_generic( + &rte_table_hash_key8_lru_dosig_ops); + if (status < 0) + return status; + + status = test_table_hash_lru_generic(&rte_table_hash_key16_lru_ops); + if (status < 0) + return status; + + status = test_table_hash_lru_generic(&rte_table_hash_key32_lru_ops); + if (status < 0) + return status; + + status = test_lru_update(); + if (status < 0) + return status; + + return 0; +} + +int +test_table_hash_ext(void) +{ + int status; + + status = test_table_hash_ext_generic(&rte_table_hash_key8_ext_ops); + if (status < 0) + return status; + + status = test_table_hash_ext_generic( + &rte_table_hash_key8_ext_dosig_ops); + if (status < 0) + return status; + + status = test_table_hash_ext_generic(&rte_table_hash_key16_ext_ops); + if (status < 0) + return status; + + status = test_table_hash_ext_generic(&rte_table_hash_key32_ext_ops); + if (status < 0) + return status; + + return 0; +} + +#endif diff --git a/app/test/test_table_tables.h b/app/test/test_table_tables.h new file mode 100644 index 0000000000..b368623410 --- /dev/null +++ b/app/test/test_table_tables.h @@ -0,0 +1,50 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 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. + */ + +/* Test prototypes */ +int test_table_lpm(void); +int test_table_lpm_ipv6(void); +int test_table_array(void); +#ifdef RTE_LIBRTE_ACL +int test_table_acl(void); +#endif +int test_table_hash_unoptimized(void); +int test_table_hash_lru(void); +int test_table_hash_ext(void); +int test_table_stub(void); + +/* Extern variables */ +typedef int (*table_test)(void); + +extern table_test table_tests[]; +extern unsigned n_table_tests; diff --git a/lib/librte_eal/common/include/rte_hexdump.h b/lib/librte_eal/common/include/rte_hexdump.h index d8176d850d..891c77bf32 100644 --- a/lib/librte_eal/common/include/rte_hexdump.h +++ b/lib/librte_eal/common/include/rte_hexdump.h @@ -39,6 +39,8 @@ * Simple API to dump out memory in a special hex format. */ +#include + #ifdef __cplusplus extern "C" { #endif -- 2.20.1