aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorKonstantin Ananyev <konstantin.ananyev@intel.com>2017-02-21 18:12:20 +0000
committerKonstantin Ananyev <konstantin.ananyev@intel.com>2017-02-24 16:37:08 +0000
commitaa97dd1ce910b839fed46ad55d1e70e403f5a930 (patch)
treef6f0fd494eaf499859bff9f20f5ddfac9ab99233 /test
parentf5f10013ffef8e4ac1071087b8492fe6380d98fe (diff)
Introduce first version of TCP code.
Supported functionality: - open/close - listen/accept/connect - send/recv In order to achieve that libtle_udp library was reworked into libtle_l4p library that supports both TCP and UDP protocols. New libtle_timer library was introduced (thanks to Cisco guys and Dave Barach <dbarach@cisco.com> for sharing their timer code with us). Sample application was also reworked significantly to support both TCP and UDP traffic handling. New UT were introduced. Change-Id: I806b05011f521e89b58db403cfdd484a37beb775 Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.awal@intel.com> Signed-off-by: Karol Latecki <karolx.latecki@intel.com> Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Diffstat (limited to 'test')
-rw-r--r--test/Makefile1
-rw-r--r--test/gtest/Makefile12
-rw-r--r--test/gtest/README82
-rw-r--r--test/gtest/main.cpp33
-rw-r--r--test/gtest/test_common.cpp276
-rw-r--r--test/gtest/test_common.h97
-rw-r--r--test/gtest/test_scapy_gen.py96
-rw-r--r--test/gtest/test_tle_ctx.cpp130
-rw-r--r--test/gtest/test_tle_ctx.h (renamed from test/gtest/test_tle_udp_ctx.h)8
-rw-r--r--test/gtest/test_tle_tcp_stream.cpp195
-rw-r--r--test/gtest/test_tle_tcp_stream.h251
-rw-r--r--test/gtest/test_tle_udp_ctx.cpp42
-rw-r--r--test/gtest/test_tle_udp_destroy.cpp4
-rw-r--r--test/gtest/test_tle_udp_destroy.h8
-rw-r--r--test/gtest/test_tle_udp_dev.cpp27
-rw-r--r--test/gtest/test_tle_udp_dev.h23
-rw-r--r--test/gtest/test_tle_udp_event.h2
-rw-r--r--test/gtest/test_tle_udp_stream.cpp78
-rw-r--r--test/gtest/test_tle_udp_stream.h200
-rw-r--r--test/gtest/test_tle_udp_stream_gen.cpp444
-rw-r--r--test/gtest/test_tle_udp_stream_gen.h541
-rw-r--r--test/timer/Makefile42
-rw-r--r--test/timer/test_timer.c272
23 files changed, 2670 insertions, 194 deletions
diff --git a/test/Makefile b/test/Makefile
index 665396f..c5cf270 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -23,5 +23,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
DIRS-y += dring
DIRS-y += gtest
+DIRS-y += timer
include $(TLDK_ROOT)/mk/tle.subdir.mk
diff --git a/test/gtest/Makefile b/test/gtest/Makefile
index ef86b9e..2598889 100644
--- a/test/gtest/Makefile
+++ b/test/gtest/Makefile
@@ -68,12 +68,16 @@ OBJ = gtest-rfc.o
# all source are stored in SRCS-y
SRCS-y += main.cpp
+SRCS-y += test_common.cpp
SRCS-y += test_tle_dring.cpp
-SRCS-y += test_tle_udp_ctx.cpp
+SRCS-y += test_tle_ctx.cpp
#SRCS-y += test_tle_udp_dev.cpp
SRCS-y += test_tle_udp_destroy.cpp
SRCS-y += test_tle_udp_event.cpp
-SRCS-y += test_tle_udp_stream.cpp
+#SRCS-y += test_tle_udp_stream.cpp
+#SRCS-y += test_tle_udp_stream_gen.cpp
+#SRCS-y += test_tle_tcp_stream.cpp
+#SRCS-y += test_tle_tcp_stream_gen.cpp
CXXFLAGS += -std=c++11
@@ -87,7 +91,7 @@ CXXFLAGS += -I$(RTE_OUTPUT)/include
LDFLAGS += -lstdc++
LDFLAGS += -L$(GMOCK_DIR) -lgmock
-LDLIBS += -ltle_udp -ltle_dring
+LDLIBS += -whole-archive -ltle_l4p -ltle_dring
include $(TLDK_ROOT)/mk/tle.cpp-obj.mk
endif
@@ -116,7 +120,7 @@ LDLIBS += gtest-rfc.o
LDLIBS += -lstdc++
LDLIBS += -L$(GMOCK_DIR) -lgmock
LDLIBS += -L$(RTE_OUTPUT)/lib
-LDLIBS += -ltle_udp -ltle_dring
+LDLIBS += -whole-archive -ltle_l4p -ltle_dring -ltle_timer
include $(TLDK_ROOT)/mk/tle.app.mk
endif
diff --git a/test/gtest/README b/test/gtest/README
index 8d39b6b..7fba5ff 100644
--- a/test/gtest/README
+++ b/test/gtest/README
@@ -1,41 +1,41 @@
-OVERVIEW
-========
-
-This application is a set of API unit tests for libtle_dring and libtle_udp
-libraries, plus a small set of functional tests for RX/TX functions in
-libtle_udp library.
-UT application needs GoogleTest C++ testing framework to compile, please
-follow installation steps below to enable them.
-
-INSTALLATION GUIDE
-==================
-Assumes that user had finished initial installation from TLDK root
-directory README.
-
-1. TLDK unit tests require pcap PMD to be available, enable it in DPDK and
- rebuild it.
- (http://dpdk.org/doc/quick-start has information how to do it)
-2. Obtain GoogleTest and build it. Some additional dependencies might be
- needed.
- (refer to https://github.com/google/googletest for information how to
- download and build it)
-3. Make sure that GTEST_DIR and GMOCK_DIR environment variables are set.
-4. Rebuild TLDK.
-
-Example:
-cd dpdk
-make config T=x86_64-native-linuxapp-gcc
-sed -ri 's,(PMD_PCAP=).*,\1y,' build/.config
-make install
-
-git clone https://github.com/google/googletest.git
-cd ../googletest
-export GTEST_DIR=`pwd`/googletest
-export GMOCK_DIR=`pwd`/googlemock
-cmake CMakeLists.txt
-make
-
-cd ../tldk
-make clean
-make all
-./x86_64-native-linuxapp-gcc/app/gtest-rfc --lcores=0
+1. OVERVIEW
+
+ This application is a set of API unit tests for libtle_dring, libtle_l4p,
+ and libtle_timer libraries, plus a small set of functional tests for RX/TX
+ functions in libtle_l4p library.
+
+ UT application needs GoogleTest C++ testing framework to compile, please
+ follow installation steps below to enable them.
+
+2. INSTALLATION GUIDE
+
+ Assumes that user had finished initial installation from TLDK root
+ directory README.
+
+ 1) TLDK unit tests require pcap PMD to be available, enable it in DPDK and
+ rebuild it. (http://dpdk.org/doc/quick-start has information how to
+ do it)
+ 2) Obtain GoogleTest and build it. Some additional dependencies might be
+ needed. (refer to https://github.com/google/googletest for information
+ how to download and build it)
+ 3) Make sure that GTEST_DIR and GMOCK_DIR environment variables are set.
+ 4) Rebuild TLDK.
+
+2.1 Example
+
+ cd dpdk
+ make config T=x86_64-native-linuxapp-gcc
+ sed -ri 's,(PMD_PCAP=).*,\1y,' build/.config
+ make install
+
+ git clone https://github.com/google/googletest.git
+ cd ../googletest
+ export GTEST_DIR=`pwd`/googletest
+ export GMOCK_DIR=`pwd`/googlemock
+ cmake CMakeLists.txt
+ make
+
+ cd ../tldk
+ make clean
+ make all
+ ./x86_64-native-linuxapp-gcc/app/gtest-rfc --lcores=0
diff --git a/test/gtest/main.cpp b/test/gtest/main.cpp
index 8c4e2dc..17cdccd 100644
--- a/test/gtest/main.cpp
+++ b/test/gtest/main.cpp
@@ -13,17 +13,30 @@
* limitations under the License.
*/
+#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
-#include <iostream>
+
#include <rte_common.h>
#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_mbuf.h>
+#include <rte_errno.h>
+
+#include "test_common.h"
-int main(int argc, char *argv[])
+struct rte_mempool *mbuf_pool;
+
+int
+main(int argc, char *argv[])
{
+ uint8_t nb_ports = 1;
+ int rc = 0;
+
/* Initialize GoogleTest&Mock and parse any args */
testing::InitGoogleMock(&argc, argv);
-
/* Initialize EAL */
int ret = rte_eal_init(argc, argv);
if (ret < 0)
@@ -31,5 +44,19 @@ int main(int argc, char *argv[])
argc -= ret;
argv += ret;
+ /*
+ * Creates a new mempool in memory to hold the mbufs.
+ * Multiplied by 2 because of mempeool to be used for packet
+ * fragmentation purposes.
+ */
+ mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
+ 2 * NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+ if (mbuf_pool == NULL) {
+ rc = -rte_errno;
+ printf("Mempool was not created, rc=%d\n", rc);
+ return rc;
+ }
+
return RUN_ALL_TESTS();
}
diff --git a/test/gtest/test_common.cpp b/test/gtest/test_common.cpp
new file mode 100644
index 0000000..0bdcebc
--- /dev/null
+++ b/test/gtest/test_common.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test_common.h"
+
+int
+port_init(uint8_t port, struct rte_mempool *mbuf_pool)
+{
+ struct rte_eth_conf port_conf;
+ const uint16_t rx_rings = 1, tx_rings = 1;
+ uint16_t q;
+ int retval;
+ int socket_id;
+
+ if (port >= rte_eth_dev_count())
+ return -1;
+
+ socket_id = rte_eth_dev_socket_id(port);
+
+ memset(&port_conf, 0, sizeof(struct rte_eth_conf));
+ port_conf.rxmode.max_rx_pkt_len = ETHER_MAX_LEN;
+
+ /* Configure the Ethernet device. */
+ retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
+ if (retval != 0)
+ return retval;
+
+ /* Allocate and set up 1 RX queue per Ethernet port. */
+ for (q = 0; q < rx_rings; q++) {
+ retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
+ socket_id, NULL, mbuf_pool);
+ if (retval < 0)
+ return retval;
+ }
+
+ /* Allocate and set up 1 TX queue per Ethernet port. */
+ for (q = 0; q < tx_rings; q++) {
+ retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
+ socket_id, NULL);
+ if (retval < 0)
+ return retval;
+ }
+
+ /* Start the Ethernet port. */
+ retval = rte_eth_dev_start(port);
+ if (retval < 0)
+ return retval;
+
+ /* Enable RX in promiscuous mode for the Ethernet device. */
+ rte_eth_promiscuous_enable(port);
+
+ return 0;
+}
+
+/* TODO: Shameless rip of examples/udpfwd/pkt.c below. Sorry Would like to
+ * move these funcions to separate lib so all future created apps could
+ * re-use that code.
+ */
+void
+fill_pkt_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t l3, uint32_t l4)
+{
+ m->l2_len = l2;
+ m->l3_len = l3;
+ m->l4_len = l4;
+ m->tso_segsz = 0;
+ m->outer_l2_len = 0;
+ m->outer_l3_len = 0;
+}
+
+int
+is_ipv4_frag(const struct ipv4_hdr *iph)
+{
+ const uint16_t mask = rte_cpu_to_be_16(~IPV4_HDR_DF_FLAG);
+
+ return ((mask & iph->fragment_offset) != 0);
+}
+
+void
+fill_ipv4_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t proto,
+ uint32_t frag)
+{
+ const struct ipv4_hdr *iph;
+ int32_t dlen, len;
+
+ dlen = rte_pktmbuf_data_len(m);
+ dlen -= l2 + sizeof(struct udp_hdr);
+
+ iph = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr *, l2);
+ len = (iph->version_ihl & IPV4_HDR_IHL_MASK) * IPV4_IHL_MULTIPLIER;
+
+ if (frag != 0 && is_ipv4_frag(iph)) {
+ m->packet_type &= ~RTE_PTYPE_L4_MASK;
+ m->packet_type |= RTE_PTYPE_L4_FRAG;
+ }
+
+ if (len > dlen || (proto <= IPPROTO_MAX && iph->next_proto_id != proto))
+ m->packet_type = RTE_PTYPE_UNKNOWN;
+ else
+ fill_pkt_hdr_len(m, l2, len, sizeof(struct udp_hdr));
+}
+
+int
+ipv6x_hdr(uint32_t proto)
+{
+ return (proto == IPPROTO_HOPOPTS ||
+ proto == IPPROTO_ROUTING ||
+ proto == IPPROTO_FRAGMENT ||
+ proto == IPPROTO_AH ||
+ proto == IPPROTO_NONE ||
+ proto == IPPROTO_DSTOPTS);
+}
+
+uint16_t
+ipv4x_cksum(const void *iph, size_t len)
+{
+ uint16_t cksum;
+
+ cksum = rte_raw_cksum(iph, len);
+ return (cksum == 0xffff) ? cksum : ~cksum;
+}
+
+void
+fill_ipv6x_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t nproto,
+ uint32_t fproto)
+{
+ const struct ip6_ext *ipx;
+ int32_t dlen, len, ofs;
+
+ len = sizeof(struct ipv6_hdr);
+
+ dlen = rte_pktmbuf_data_len(m);
+ dlen -= l2 + sizeof(struct udp_hdr);
+
+ ofs = l2 + len;
+ ipx = rte_pktmbuf_mtod_offset(m, const struct ip6_ext *, ofs);
+
+ while (ofs > 0 && len < dlen) {
+
+ switch (nproto) {
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_ROUTING:
+ case IPPROTO_DSTOPTS:
+ ofs = (ipx->ip6e_len + 1) << 3;
+ break;
+ case IPPROTO_AH:
+ ofs = (ipx->ip6e_len + 2) << 2;
+ break;
+ case IPPROTO_FRAGMENT:
+ /*
+ * tso_segsz is not used by RX, so suse it as temporary
+ * buffer to store the fragment offset.
+ */
+ m->tso_segsz = ofs;
+ ofs = sizeof(struct ip6_frag);
+ m->packet_type &= ~RTE_PTYPE_L4_MASK;
+ m->packet_type |= RTE_PTYPE_L4_FRAG;
+ break;
+ default:
+ ofs = 0;
+ }
+
+ if (ofs > 0) {
+ nproto = ipx->ip6e_nxt;
+ len += ofs;
+ ipx += ofs / sizeof(*ipx);
+ }
+ }
+
+ /* undercognised or invalid packet. */
+ if ((ofs == 0 && nproto != fproto) || len > dlen)
+ m->packet_type = RTE_PTYPE_UNKNOWN;
+ else
+ fill_pkt_hdr_len(m, l2, len, sizeof(struct udp_hdr));
+}
+
+void
+fill_ipv6_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t fproto)
+{
+ const struct ipv6_hdr *iph;
+
+ iph = rte_pktmbuf_mtod_offset(m, const struct ipv6_hdr *,
+ sizeof(struct ether_hdr));
+
+ if (iph->proto == fproto)
+ fill_pkt_hdr_len(m, l2, sizeof(struct ipv6_hdr),
+ sizeof(struct udp_hdr));
+ else if (ipv6x_hdr(iph->proto) != 0)
+ fill_ipv6x_hdr_len(m, l2, iph->proto, fproto);
+}
+
+void
+fill_eth_hdr_len(struct rte_mbuf *m)
+{
+ uint32_t dlen, l2;
+ uint16_t etp;
+ const struct ether_hdr *eth;
+
+ dlen = rte_pktmbuf_data_len(m);
+
+ /* check that first segment is at least 42B long. */
+ if (dlen < sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
+ sizeof(struct udp_hdr)) {
+ m->packet_type = RTE_PTYPE_UNKNOWN;
+ return;
+ }
+
+ l2 = sizeof(*eth);
+
+ eth = rte_pktmbuf_mtod(m, const struct ether_hdr *);
+ etp = eth->ether_type;
+ if (etp == rte_be_to_cpu_16(ETHER_TYPE_VLAN))
+ l2 += sizeof(struct vlan_hdr);
+
+ if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv4)) {
+ m->packet_type = RTE_PTYPE_L4_UDP |
+ RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+ RTE_PTYPE_L2_ETHER;
+ fill_ipv4_hdr_len(m, l2, IPPROTO_UDP, 1);
+ } else if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv6) &&
+ dlen >= l2 + sizeof(struct ipv6_hdr) +
+ sizeof(struct udp_hdr)) {
+ m->packet_type = RTE_PTYPE_L4_UDP |
+ RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+ RTE_PTYPE_L2_ETHER;
+ fill_ipv6_hdr_len(m, l2, IPPROTO_UDP);
+ } else
+ m->packet_type = RTE_PTYPE_UNKNOWN;
+}
+
+/*
+ * generic, assumes HW doesn't recognise any packet type.
+ */
+uint16_t
+typen_rx_callback(uint8_t port, __rte_unused uint16_t queue,
+ struct rte_mbuf *pkt[], uint16_t nb_pkts,
+ __rte_unused uint16_t max_pkts, void *user_param)
+{
+ uint32_t j;
+
+ for (j = 0; j != nb_pkts; j++) {
+ fill_eth_hdr_len(pkt[j]);
+
+ }
+
+ return nb_pkts;
+}
+
+int
+dummy_lookup4(void *opaque, const struct in_addr *addr, struct tle_dest *res)
+{
+ RTE_SET_USED(opaque);
+ RTE_SET_USED(addr);
+ RTE_SET_USED(res);
+ return -ENOENT;
+}
+
+int
+dummy_lookup6(void *opaque, const struct in6_addr *addr, struct tle_dest *res)
+{
+ RTE_SET_USED(opaque);
+ RTE_SET_USED(addr);
+ RTE_SET_USED(res);
+ return -ENOENT;
+}
diff --git a/test/gtest/test_common.h b/test/gtest/test_common.h
new file mode 100644
index 0000000..2eb93e4
--- /dev/null
+++ b/test/gtest/test_common.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_COMMON_H_
+#define TEST_COMMON_H_
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <rte_config.h>
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_eal.h>
+#include <rte_lcore.h>
+#include <rte_ethdev.h>
+#include <rte_kvargs.h>
+#include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_cycles.h>
+#include <rte_lpm.h>
+#include <rte_lpm6.h>
+#include <rte_hash.h>
+#include <rte_ip.h>
+#include <rte_ip_frag.h>
+#include <rte_udp.h>
+
+#define RX_RING_SIZE 128
+#define TX_RING_SIZE 128
+#define NUM_MBUFS 4095
+#define MBUF_CACHE_SIZE 250
+#define BURST_SIZE 32
+
+extern struct rte_mempool *mbuf_pool;
+extern struct rte_mempool *frag_mp;
+
+int port_init(uint8_t port, struct rte_mempool *mbuf_pool);
+
+uint64_t
+_mbuf_tx_offload(uint64_t il2, uint64_t il3, uint64_t il4, uint64_t tso,
+ uint64_t ol3, uint64_t ol2);
+
+void
+fill_pkt_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t l3, uint32_t l4);
+
+int
+is_ipv4_frag(const struct ipv4_hdr *iph);
+
+void
+fill_ipv4_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t proto,
+ uint32_t frag);
+
+int
+ipv6x_hdr(uint32_t proto);
+
+uint16_t
+ipv4x_cksum(const void *iph, size_t len);
+
+void
+fill_ipv6x_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t nproto,
+ uint32_t fproto);
+
+void
+fill_ipv6_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t fproto);
+
+void
+fix_reassembled(struct rte_mbuf *m, int32_t hwcsum);
+
+uint32_t
+compress_pkt_list(struct rte_mbuf *pkt[], uint32_t nb_pkt, uint32_t nb_zero);
+
+void
+fill_eth_hdr_len(struct rte_mbuf *m);
+
+uint16_t
+typen_rx_callback(uint8_t port, __rte_unused uint16_t queue,
+ struct rte_mbuf *pkt[], uint16_t nb_pkts,
+ __rte_unused uint16_t max_pkts, void *user_param);
+
+int
+dummy_lookup4(void *opaque, const struct in_addr *addr, struct tle_dest *res);
+
+int
+dummy_lookup6(void *opaque, const struct in6_addr *addr, struct tle_dest *res);
+
+#endif /* TEST_COMMON_H_ */
diff --git a/test/gtest/test_scapy_gen.py b/test/gtest/test_scapy_gen.py
new file mode 100644
index 0000000..aecbe5f
--- /dev/null
+++ b/test/gtest/test_scapy_gen.py
@@ -0,0 +1,96 @@
+# Copyright (c) 2016 Intel Corporation.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+from socket import inet_pton
+import logging
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+from scapy.all import *
+from scapy.layers.inet import IP
+from scapy.layers.inet6 import IPv6
+from scapy.layers.inet import UDP
+from random import shuffle
+
+src_mac = "00:00:00:00:de:ad"
+dst_mac = "00:00:de:ad:be:ef"
+eth_hdr_len = len(Ether())
+ip_hdr_len = len(IP())
+ipv6_hdr_len = len(IPv6())
+udp_hdr_len = len(UDP())
+udpv4_hdr_len = eth_hdr_len + ip_hdr_len + udp_hdr_len
+udpv6_hdr_len = eth_hdr_len + ipv6_hdr_len + udp_hdr_len
+
+
+def write_pkts(pkts, pcap_path):
+ try:
+ pktdump = PcapWriter(pcap_path, append=False, sync=True)
+ if len(pkts) > 0:
+ pktdump.write(pkts)
+ except IOError:
+ pass
+
+
+def read_pkts(pcap_path):
+ try:
+ pkts_ref = PcapReader(pcap_path)
+ pkts = pkts_ref.read_all()
+ return list(pkts)
+ except IOError:
+ pkts = []
+ return pkts
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Generate packets for"
+ "TLDK rx/tx tests")
+ parser.add_argument("l_ip")
+ parser.add_argument("r_ip")
+ parser.add_argument("l_port", type=int)
+ parser.add_argument("r_port", type=int)
+ parser.add_argument("nb_pkts", type=int)
+ parser.add_argument("file")
+ parser.add_argument("-bc3", "--bad_chksum_l3", default=None, type=int)
+ parser.add_argument("-bc4", "--bad_chksum_l4", default=None, type=int)
+ parser.add_argument("-f", "--fragment")
+ parser.add_argument("-r", "--rand-pkt-size")
+
+ args = parser.parse_args()
+
+ ip_ver = ""
+ try:
+ inet_pton(socket.AF_INET, args.l_ip)
+ ip_ver = "ipv4"
+ except socket.error:
+ ip_ver = "ipv6"
+
+ pkts = read_pkts(args.file)
+
+ if "ipv4" in ip_ver:
+ for i in range(0, args.nb_pkts):
+ pkt = Ether(dst=dst_mac, src=src_mac) /\
+ IP(src=args.l_ip, dst=args.r_ip, frag=0, chksum=args.bad_chksum_l3) /\
+ UDP(sport=args.l_port, dport=args.r_port, chksum=args.bad_chksum_l4) /\
+ Raw(RandString(size=(100 - udpv4_hdr_len)))
+ pkts.append(pkt)
+ else:
+ for i in range(0, args.nb_pkts):
+ pkt = Ether(dst=dst_mac, src=src_mac) /\
+ IPv6(src=args.l_ip, dst=args.r_ip) /\
+ UDP(sport=args.l_port, dport=args.r_port, chksum=args.bad_chksum_l4) / \
+ Raw(RandString(size=(100 - udpv6_hdr_len)))
+ pkts.append(pkt)
+
+ shuffle(pkts)
+ write_pkts(pkts, args.file)
+
+main()
diff --git a/test/gtest/test_tle_ctx.cpp b/test/gtest/test_tle_ctx.cpp
new file mode 100644
index 0000000..b9808ee
--- /dev/null
+++ b/test/gtest/test_tle_ctx.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test_tle_ctx.h"
+
+TEST(ctx_create, ctx_create_null)
+{
+ struct tle_ctx *ctx;
+
+ ctx = tle_ctx_create(NULL);
+ ASSERT_EQ(ctx, (struct tle_ctx *) NULL);
+ ASSERT_EQ(rte_errno, EINVAL);
+}
+
+TEST(ctx_create, create_invalid_socket)
+{
+ struct tle_ctx *ctx;
+ struct tle_ctx_param prm;
+
+ memset(&prm, 0, sizeof(prm));
+ prm.socket_id = SOCKET_ID_ANY;
+ prm.max_streams = 0x10;
+ prm.max_stream_rbufs = 0x100;
+ prm.max_stream_sbufs = 0x100;
+
+ ctx = tle_ctx_create(NULL);
+ ASSERT_EQ(ctx, (struct tle_ctx *) NULL);
+ ASSERT_EQ(rte_errno, EINVAL);
+}
+
+TEST(ctx_create, ctx_create_proto_invalid)
+{
+ struct tle_ctx *ctx;
+ struct tle_ctx_param prm;
+
+ memset(&prm, 0, sizeof(prm));
+ prm.socket_id = SOCKET_ID_ANY;
+ prm.proto = TLE_PROTO_NUM;
+ prm.max_streams = 0x10;
+ prm.max_stream_rbufs = 0x100;
+ prm.max_stream_sbufs = 0x100;
+
+ ctx = tle_ctx_create(NULL);
+ ASSERT_EQ(ctx, (struct tle_ctx *) NULL);
+ ASSERT_EQ(rte_errno, EINVAL);
+}
+
+TEST(ctx_create, ctx_create_proto_not_spec)
+{
+ struct tle_ctx *ctx;
+ struct tle_ctx_param prm;
+
+ memset(&prm, 0, sizeof(prm));
+ prm.socket_id = SOCKET_ID_ANY;
+ prm.max_streams = 0x10;
+ prm.max_stream_rbufs = 0x100;
+ prm.max_stream_sbufs = 0x100;
+
+ ctx = tle_ctx_create(&prm);
+ ASSERT_NE(ctx, (void *)NULL);
+
+ tle_ctx_destroy(ctx);
+}
+
+TEST(ctx_create, ctx_create_proto_udp)
+{
+ struct tle_ctx *ctx;
+ struct tle_ctx_param prm;
+
+ memset(&prm, 0, sizeof(prm));
+ prm.socket_id = SOCKET_ID_ANY;
+ prm.proto = TLE_PROTO_UDP;
+ prm.max_streams = 0x10;
+ prm.max_stream_rbufs = 0x100;
+ prm.max_stream_sbufs = 0x100;
+
+ ctx = tle_ctx_create(&prm);
+ ASSERT_NE(ctx, (void *)NULL);
+
+ tle_ctx_destroy(ctx);
+}
+
+TEST(ctx_create, ctx_create_proto_tcp)
+{
+ struct tle_ctx *ctx;
+ struct tle_ctx_param prm;
+
+ memset(&prm, 0, sizeof(prm));
+ prm.socket_id = SOCKET_ID_ANY;
+ prm.proto = TLE_PROTO_TCP;
+ prm.max_streams = 0x10;
+ prm.max_stream_rbufs = 0x100;
+ prm.max_stream_sbufs = 0x100;
+
+ ctx = tle_ctx_create(&prm);
+ ASSERT_NE(ctx, (void *)NULL);
+
+ tle_ctx_destroy(ctx);
+}
+
+TEST(ctx_create, ctx_create_invalidate)
+{
+ struct tle_ctx *ctx;
+ struct tle_ctx_param prm;
+
+ memset(&prm, 0, sizeof(prm));
+ prm.socket_id = SOCKET_ID_ANY;
+ prm.max_streams = 0x10;
+ prm.max_stream_rbufs = 0x100;
+ prm.max_stream_sbufs = 0x100;
+
+ ctx = tle_ctx_create(&prm);
+ ASSERT_NE(ctx, (void *)NULL);
+
+ tle_ctx_invalidate(ctx);
+
+ tle_ctx_destroy(ctx);
+}
diff --git a/test/gtest/test_tle_udp_ctx.h b/test/gtest/test_tle_ctx.h
index af02440..5c6f2c3 100644
--- a/test/gtest/test_tle_udp_ctx.h
+++ b/test/gtest/test_tle_ctx.h
@@ -13,11 +13,11 @@
* limitations under the License.
*/
-#ifndef TEST_TLE_UDP_CTX_H_
-#define TEST_TLE_UDP_CTX_H_
+#ifndef TEST_TLE_CTX_H_
+#define TEST_TLE_CTX_H_
#include <gtest/gtest.h>
#include <rte_errno.h>
-#include <tle_udp_impl.h>
+#include <tle_ctx.h>
-#endif /* TEST_TLE_UDP_CTX_H_ */
+#endif /* TEST_TLE_CTX_H_ */
diff --git a/test/gtest/test_tle_tcp_stream.cpp b/test/gtest/test_tle_tcp_stream.cpp
new file mode 100644
index 0000000..b861049
--- /dev/null
+++ b/test/gtest/test_tle_tcp_stream.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test_tle_tcp_stream.h"
+
+/* --------- Basic tests for opening / closing streams, no traffic --------- */
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_open_nullctx)
+{
+ stream = tle_tcp_stream_open(nullptr,
+ (const struct tle_tcp_stream_param *)&stream_prm);
+ EXPECT_EQ(stream, nullptr);
+ EXPECT_EQ(rte_errno, EINVAL);
+
+ ret = tle_tcp_stream_close(stream);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_open_null_stream_prm)
+{
+ stream = tle_tcp_stream_open(ctx, nullptr);
+ EXPECT_EQ(stream, nullptr);
+ EXPECT_EQ(rte_errno, EINVAL);
+
+ ret = tle_tcp_stream_close(stream);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_open_close_ipv4)
+{
+ stream = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm);
+ ASSERT_NE(stream, nullptr);
+
+ ret = tle_tcp_stream_close(stream);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_open_close_ipv6)
+{
+ stream6 = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm6);
+ ASSERT_NE(stream, nullptr);
+
+ ret = tle_tcp_stream_close(stream6);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_open_close_open_close)
+{
+ stream = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm);
+ ASSERT_NE(stream, nullptr);
+
+ ret = tle_tcp_stream_close(stream);
+ ASSERT_EQ(ret, 0);
+
+ stream = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param*)&stream_prm);
+ ASSERT_NE(stream, nullptr);
+
+ ret = tle_tcp_stream_close(stream);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_open_duplicate_ipv4)
+{
+ struct tle_stream *stream_dup;
+
+ stream = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm);
+ ASSERT_NE(stream, nullptr);
+
+ stream_dup = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param*)&stream_prm);
+ ASSERT_EQ(stream_dup, nullptr);
+ ASSERT_EQ(rte_errno, EEXIST);
+
+ ret = tle_tcp_stream_close(stream);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_open_duplicate_ipv6)
+{
+ struct tle_stream *stream_dup;
+
+ stream6 = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm6);
+ ASSERT_NE(stream, nullptr);
+
+ stream_dup = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param*)&stream_prm6);
+ ASSERT_EQ(stream_dup, nullptr);
+ ASSERT_EQ(rte_errno, EEXIST);
+
+ ret = tle_tcp_stream_close(stream6);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_close_null)
+{
+ ret = tle_tcp_stream_close(nullptr);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(test_tle_tcp_stream, tcp_stream_test_closed_already)
+{
+ stream = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm);
+ ASSERT_NE(stream, nullptr);
+
+ ret = tle_tcp_stream_close(stream);
+ EXPECT_EQ(ret, 0);
+
+ ret = tle_tcp_stream_close(stream);
+ EXPECT_NE(ret, 0);
+}
+
+/* --------- Tests for get_addr call --------- */
+
+TEST_F(test_tle_tcp_stream_ops, tcp_stream_get_addr_null_stream)
+{
+ struct tle_tcp_stream_addr addr;
+
+ ret = tle_tcp_stream_get_addr(nullptr, &addr);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(test_tle_tcp_stream_ops, tcp_stream_get_addr_null_addr)
+{
+ ret = tle_tcp_stream_get_addr(stream, NULL);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(test_tle_tcp_stream_ops, tcp_stream_get_addr_ipv4)
+{
+ struct tle_tcp_stream_addr addr;
+
+ memset(&addr, 0, sizeof(addr));
+ ret = tle_tcp_stream_get_addr(stream, &addr);
+ ASSERT_EQ(ret, 0);
+
+ ret = memcmp(&addr, &stream_prm.addr, sizeof(tle_tcp_stream_addr));
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(test_tle_tcp_stream_ops, tcp_stream_get_addr_ipv6)
+{
+ struct tle_tcp_stream_addr addr;
+
+ memset(&addr, 0, sizeof(addr));
+ ret = tle_tcp_stream_get_addr(stream6, &addr);
+ ASSERT_EQ(ret, 0);
+
+ ret = memcmp(&addr, &stream_prm6.addr, sizeof(tle_tcp_stream_addr));
+ ASSERT_EQ(ret, 0);
+}
+
+/* --------- Basic tests for listen call, no incoming connections --------- */
+
+TEST_F(test_tle_tcp_stream_ops, tcp_stream_listen_null_stream)
+{
+ ret = tle_tcp_stream_listen(nullptr);
+ EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(test_tle_tcp_stream_ops, tcp_stream_listen_ipv4)
+{
+ ret = tle_tcp_stream_listen(stream);
+ ASSERT_EQ(ret, 0);
+
+ ret = tle_tcp_stream_close(stream);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(test_tle_tcp_stream_ops, tcp_stream_listen_ipv6)
+{
+ ret = tle_tcp_stream_listen(stream6);
+ ASSERT_EQ(ret, 0);
+
+ ret = tle_tcp_stream_close(stream6);
+ ASSERT_EQ(ret, 0);
+}
diff --git a/test/gtest/test_tle_tcp_stream.h b/test/gtest/test_tle_tcp_stream.h
new file mode 100644
index 0000000..2caf2b5
--- /dev/null
+++ b/test/gtest/test_tle_tcp_stream.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_TLE_TCP_STREAM_H_
+#define TEST_TLE_TCP_STREAM_H_
+
+#include <iostream>
+#include <arpa/inet.h>
+#include <netinet/ip6.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <rte_errno.h>
+
+#include <tle_event.h>
+#include <tle_ctx.h>
+#include <tle_tcp.h>
+
+#include "test_common.h"
+
+#define MAX_STREAMS 0x100
+#define MAX_STREAM_RBUFS 0x100
+#define MAX_STREAM_SBUFS 0x100
+#define RX_NO_OFFLOAD 0x0
+#define TX_NO_OFFLOAD 0x0
+
+static struct tle_ctx_param ctx_prm_tmpl = {
+ .socket_id = SOCKET_ID_ANY,
+ .proto = TLE_PROTO_TCP,
+ .max_streams = MAX_STREAMS,
+ .max_stream_rbufs = MAX_STREAM_RBUFS,
+ .max_stream_sbufs = MAX_STREAM_SBUFS,
+};
+
+static struct tle_dev_param dev_prm_tmpl = {
+ .rx_offload = RX_NO_OFFLOAD,
+ .tx_offload = TX_NO_OFFLOAD
+};
+
+class tcp_stream_base: public ::testing::Test {
+
+public:
+ struct tle_ctx *setup_ctx(struct tle_ctx_param *prm);
+ struct tle_dev *setup_dev(struct tle_ctx *ctx,
+ struct tle_dev_param *dev_prm);
+ void setup_dev_prm(struct tle_dev_param *dev_prm,
+ char const *ipv4, char const *ipv6);
+ int setup_stream_prm(struct tle_tcp_stream_param *stream_prm,
+ char const *l_ip, char const *r_ip,
+ int l_port, int r_port);
+ struct tle_evq *setup_event();
+};
+
+struct tle_evq
+*tcp_stream_base::setup_event()
+{
+ int32_t socket_id;
+ uint32_t max_events;
+ struct tle_evq_param evq_params;
+ struct tle_evq *evq;
+
+ socket_id = SOCKET_ID_ANY;
+ max_events = 10;
+ rte_errno = 0;
+ memset(&evq_params, 0, sizeof(struct tle_evq_param));
+ evq_params.socket_id = socket_id;
+ evq_params.max_events = max_events;
+ evq = tle_evq_create(&evq_params);
+ return evq;
+}
+
+struct tle_ctx
+*tcp_stream_base::setup_ctx(struct tle_ctx_param *prm)
+{
+ struct tle_ctx *ctx;
+
+ prm->lookup4 = dummy_lookup4;
+ prm->lookup6 = dummy_lookup6;
+
+ ctx = tle_ctx_create(prm);
+
+ return ctx;
+}
+
+struct tle_dev
+*tcp_stream_base::setup_dev(struct tle_ctx *ctx, struct tle_dev_param *dev_prm)
+{
+ struct tle_dev *dev;
+
+ dev = tle_add_dev(ctx, dev_prm);
+
+ return dev;
+}
+
+void
+tcp_stream_base::setup_dev_prm(struct tle_dev_param *dev_prm, char const *ipv4,
+ char const *ipv6)
+{
+ inet_pton(AF_INET, ipv4, &dev_prm->local_addr4);
+ inet_pton(AF_INET6, ipv6, &dev_prm->local_addr6);
+}
+
+int
+tcp_stream_base::setup_stream_prm(struct tle_tcp_stream_param *stream_prm,
+ char const *l_ip, char const *r_ip, int l_port, int r_port)
+{
+ int32_t ret;
+ struct sockaddr_in *ip4_addr;
+ struct sockaddr_in6 *ip6_addr;
+ struct addrinfo hint, *res = NULL;
+ struct tle_tcp_stream_cfg stream_cfg;
+
+ memset(&hint, '\0', sizeof(hint));
+ memset(&stream_cfg, 0, sizeof(stream_cfg));
+
+ ret = getaddrinfo(l_ip, NULL, &hint, &res);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (res->ai_family == AF_INET) {
+ ip4_addr = (struct sockaddr_in *) &stream_prm->addr.local;
+ ip4_addr->sin_family = AF_INET;
+ ip4_addr->sin_port = htons(l_port);
+ ip4_addr->sin_addr.s_addr = inet_addr(l_ip);
+ } else if (res->ai_family == AF_INET6) {
+ ip6_addr = (struct sockaddr_in6 *) &stream_prm->addr.local;
+ ip6_addr->sin6_family = AF_INET6;
+ inet_pton(AF_INET6, l_ip, &ip6_addr->sin6_addr);
+ ip6_addr->sin6_port = htons(l_port);
+ } else {
+ freeaddrinfo(res);
+ return -EINVAL;
+ }
+ freeaddrinfo(res);
+
+ memset(&hint, '\0', sizeof(hint));
+ ret = getaddrinfo(r_ip, NULL, &hint, &res);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (res->ai_family == AF_INET) {
+ ip4_addr = (struct sockaddr_in *) &stream_prm->addr.remote;
+ ip4_addr->sin_family = AF_INET;
+ ip4_addr->sin_port = htons(r_port);
+ ip4_addr->sin_addr.s_addr = inet_addr(r_ip);
+ } else if (res->ai_family == AF_INET6) {
+ ip6_addr = (struct sockaddr_in6 *) &stream_prm->addr.remote;
+ ip6_addr->sin6_family = AF_INET6;
+ inet_pton(AF_INET6, r_ip, &ip6_addr->sin6_addr);
+ ip6_addr->sin6_port = htons(r_port);
+ } else {
+ freeaddrinfo(res);
+ return -EINVAL;
+ }
+ freeaddrinfo(res);
+
+ stream_prm->cfg = stream_cfg;
+
+ return 0;
+}
+
+class test_tle_tcp_stream: public ::tcp_stream_base {
+protected:
+ virtual void SetUp(void)
+ {
+ ipv4_laddr = "192.0.0.1";
+ ipv4_raddr = "192.0.0.2";
+ ipv6_laddr = "2001::1000";
+ ipv6_raddr = "2001::2000";
+ l_port = 10000;
+ r_port = 10000;
+
+ memset(&ctx_prm, 0, sizeof(ctx_prm));
+ memset(&dev_prm, 0, sizeof(dev_prm));
+ memset(&stream_prm, 0, sizeof(stream_prm));
+ memset(&stream_prm6, 0, sizeof(stream_prm6));
+
+ ctx_prm = ctx_prm_tmpl;
+ dev_prm = dev_prm_tmpl;
+ setup_dev_prm(&dev_prm, ipv4_laddr, ipv6_laddr);
+ ret = setup_stream_prm(&stream_prm, ipv4_laddr, ipv4_raddr,
+ l_port, r_port);
+ ASSERT_EQ(ret, 0);
+ setup_stream_prm(&stream_prm6, ipv6_laddr, ipv6_raddr, l_port,
+ r_port);
+ ASSERT_EQ(ret, 0);
+
+ ctx = setup_ctx(&ctx_prm);
+ ASSERT_NE(ctx, (void *) NULL);
+ dev = setup_dev(ctx, &dev_prm);
+ ASSERT_NE(dev, (void *) NULL);
+ }
+
+ virtual void TearDown(void)
+ {
+ ret = 0;
+ tle_del_dev(dev);
+ tle_ctx_destroy(ctx);
+ }
+
+ int ret;
+ struct tle_ctx *ctx;
+ struct tle_dev *dev;
+ struct tle_stream *stream;
+ struct tle_stream *stream6;
+
+ struct tle_ctx_param ctx_prm;
+ struct tle_dev_param dev_prm;
+ struct tle_tcp_stream_param stream_prm;
+ struct tle_tcp_stream_param stream_prm6;
+
+ int l_port, r_port;
+ char const *ipv4_laddr;
+ char const *ipv4_raddr;
+ char const *ipv6_laddr;
+ char const *ipv6_raddr;
+};
+
+class test_tle_tcp_stream_ops: public ::test_tle_tcp_stream {
+public:
+ virtual void SetUp(void)
+ {
+ test_tle_tcp_stream::SetUp();
+ stream = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm);
+ stream6 = tle_tcp_stream_open(ctx,
+ (const struct tle_tcp_stream_param *)&stream_prm6);
+ }
+
+ virtual void TearDown(void)
+ {
+ tle_tcp_stream_close(stream6);
+ tle_tcp_stream_close(stream);
+ test_tle_tcp_stream::TearDown();
+ }
+};
+
+#endif /* TEST_TLE_TCP_STREAM_H_ */
diff --git a/test/gtest/test_tle_udp_ctx.cpp b/test/gtest/test_tle_udp_ctx.cpp
deleted file mode 100644
index 0bad39f..0000000
--- a/test/gtest/test_tle_udp_ctx.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2016 Intel Corporation.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "test_tle_udp_ctx.h"
-
-TEST(udp_ctx, udp_create_null)
-{
- struct tle_udp_ctx *ctx;
-
- ctx = tle_udp_create(NULL);
- ASSERT_EQ(ctx, (struct tle_udp_ctx *) NULL);
- ASSERT_EQ(rte_errno, EINVAL);
-}
-
-TEST(udp_ctx, udp_create)
-{
- struct tle_udp_ctx *ctx;
- struct tle_udp_ctx_param prm;
-
- memset(&prm, 0, sizeof(prm));
- prm.socket_id = SOCKET_ID_ANY;
- prm.max_streams = 0x10;
- prm.max_stream_rbufs = 0x100;
- prm.max_stream_sbufs = 0x100;
-
- ctx = tle_udp_create(&prm);
- ASSERT_NE(ctx, (void *)NULL);
-
- tle_udp_destroy(ctx);
-}
diff --git a/test/gtest/test_tle_udp_destroy.cpp b/test/gtest/test_tle_udp_destroy.cpp
index 2244b18..2f26dd8 100644
--- a/test/gtest/test_tle_udp_destroy.cpp
+++ b/test/gtest/test_tle_udp_destroy.cpp
@@ -17,13 +17,13 @@
TEST(udp_destroy_null, udp_destroy_null)
{
- tle_udp_destroy(NULL);
+ tle_ctx_destroy(NULL);
EXPECT_EQ(rte_errno, EINVAL);
}
TEST_F(udp_destroy, udp_destroy_positive)
{
int rc;
- tle_udp_destroy(ctx);
+ tle_ctx_destroy(ctx);
ASSERT_EQ(rte_errno, 0);
}
diff --git a/test/gtest/test_tle_udp_destroy.h b/test/gtest/test_tle_udp_destroy.h
index d52376e..37bcceb 100644
--- a/test/gtest/test_tle_udp_destroy.h
+++ b/test/gtest/test_tle_udp_destroy.h
@@ -18,13 +18,13 @@
#include <gtest/gtest.h>
#include <rte_errno.h>
-#include <tle_udp_impl.h>
+#include <tle_ctx.h>
class udp_destroy : public ::testing::Test {
protected:
- struct tle_udp_ctx *ctx;
- struct tle_udp_ctx_param prm;
+ struct tle_ctx *ctx;
+ struct tle_ctx_param prm;
virtual void SetUp(void)
{
@@ -35,7 +35,7 @@ protected:
prm.max_stream_rbufs = 0x100;
prm.max_stream_sbufs = 0x100;
- ctx = tle_udp_create(&prm);
+ ctx = tle_ctx_create(&prm);
ASSERT_NE(ctx, (void *) NULL);
}
diff --git a/test/gtest/test_tle_udp_dev.cpp b/test/gtest/test_tle_udp_dev.cpp
index a58186e..93d6c5e 100644
--- a/test/gtest/test_tle_udp_dev.cpp
+++ b/test/gtest/test_tle_udp_dev.cpp
@@ -17,14 +17,14 @@
TEST_F(udp_dev, udp_dev_add_null_ctx)
{
- dev = tle_udp_add_dev(NULL, &dev_prm);
+ dev = tle_add_dev(NULL, &dev_prm);
EXPECT_EQ(dev, (void *) NULL);
EXPECT_EQ(rte_errno, EINVAL);
}
TEST_F(udp_dev, udp_dev_add_null_dev_prm)
{
- dev = tle_udp_add_dev(ctx, NULL);
+ dev = tle_add_dev(ctx, NULL);
EXPECT_EQ(dev, (void *) NULL);
EXPECT_EQ(rte_errno, EINVAL);
}
@@ -33,7 +33,7 @@ TEST_F(udp_dev, udp_dev_add_no_addr)
{
memset(&(dev_prm).local_addr4, 0, sizeof(struct in_addr));
memset(&(dev_prm).local_addr6, 0, sizeof(struct in6_addr));
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
EXPECT_EQ(dev, (void *) NULL);
EXPECT_EQ(rte_errno, EINVAL);
}
@@ -42,7 +42,7 @@ TEST_F(udp_dev, udp_dev_add_anyaddr)
{
inet_pton(AF_INET, "0.0.0.0", &(dev_prm).local_addr4);
inet_pton(AF_INET6, "::0", &(dev_prm).local_addr6);
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
EXPECT_EQ(dev, (void *) NULL);
EXPECT_EQ(rte_errno, EINVAL);
}
@@ -50,7 +50,7 @@ TEST_F(udp_dev, udp_dev_add_anyaddr)
TEST_F(udp_dev, udp_dev_add_only_ipv4)
{
memset(&(dev_prm).local_addr6, 0, sizeof(struct in6_addr));
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
ASSERT_NE(dev, (void *) NULL);
EXPECT_EQ(rte_errno, 0);
devs.push_back(dev);
@@ -59,16 +59,17 @@ TEST_F(udp_dev, udp_dev_add_only_ipv4)
TEST_F(udp_dev, udp_dev_add_only_ipv6)
{
memset(&(dev_prm).local_addr4, 0, sizeof(struct in_addr));
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
ASSERT_NE(dev, (void *) NULL);
EXPECT_EQ(rte_errno, 0);
+ devs.push_back(dev);
}
TEST_F(udp_dev, udp_dev_add_nonexist_ipv4)
{
memset(&(dev_prm).local_addr4, 0, sizeof(struct in_addr));
inet_pton(AF_INET, "10.0.0.1", &(dev_prm).local_addr4);
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
ASSERT_NE(dev, (void *) NULL);
EXPECT_EQ(rte_errno, 0);
devs.push_back(dev);
@@ -76,7 +77,7 @@ TEST_F(udp_dev, udp_dev_add_nonexist_ipv4)
TEST_F(udp_dev, udp_dev_add_positive)
{
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
ASSERT_NE(dev, (void *) NULL);
EXPECT_EQ(rte_errno, 0);
devs.push_back(dev);
@@ -86,27 +87,27 @@ TEST_F(udp_dev, udp_dev_add_max)
{
int i;
for(i = 0; i < RTE_MAX_ETHPORTS; i++) {
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
ASSERT_NE(dev, (void *) NULL);
EXPECT_EQ(rte_errno, 0);
devs.push_back(dev);
}
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
ASSERT_EQ(dev, (void *) NULL);
EXPECT_EQ(rte_errno, ENODEV);
}
TEST_F(udp_dev, udp_dev_del_positive)
{
- dev = tle_udp_add_dev(ctx, &dev_prm);
+ dev = tle_add_dev(ctx, &dev_prm);
ASSERT_NE(dev, (void *) NULL);
EXPECT_EQ(rte_errno, 0);
devs.push_back(dev);
- ASSERT_EQ(tle_udp_del_dev(dev), 0);
+ ASSERT_EQ(tle_del_dev(dev), 0);
EXPECT_EQ(rte_errno, 0);
}
TEST_F(udp_dev, udp_dev_del_null_dev)
{
- ASSERT_EQ(tle_udp_del_dev(dev), -EINVAL);
+ ASSERT_EQ(tle_del_dev(dev), -EINVAL);
}
diff --git a/test/gtest/test_tle_udp_dev.h b/test/gtest/test_tle_udp_dev.h
index 02f544d..3eeef3a 100644
--- a/test/gtest/test_tle_udp_dev.h
+++ b/test/gtest/test_tle_udp_dev.h
@@ -21,8 +21,7 @@
#include <gtest/gtest.h>
#include <rte_errno.h>
-
-#include <tle_udp_impl.h>
+#include <tle_ctx.h>
#define RX_NO_OFFLOAD 0
#define TX_NO_OFFLOAD 0
@@ -32,11 +31,11 @@ using namespace std;
class udp_dev : public ::testing::Test {
public:
- struct tle_udp_ctx *ctx;
- struct tle_udp_dev *dev;
- struct tle_udp_ctx_param prm;
- struct tle_udp_dev_param dev_prm;
- vector<tle_udp_dev*> devs;
+ struct tle_ctx *ctx;
+ struct tle_dev *dev;
+ struct tle_ctx_param prm;
+ struct tle_dev_param dev_prm;
+ vector<tle_dev *> devs;
virtual void SetUp(void)
{
@@ -56,16 +55,16 @@ public:
inet_pton(AF_INET6, "fe80::21e:67ff:fec2:2568",
&(dev_prm).local_addr6);
- ctx = tle_udp_create(&prm);
+ ctx = tle_ctx_create(&prm);
ASSERT_NE(ctx, (void *) NULL);
}
virtual void TearDown(void)
{
- for(auto d : devs) {
- tle_udp_del_dev(d);
- }
- tle_udp_destroy(ctx);
+ for (auto d : devs)
+ tle_del_dev(d);
+
+ tle_ctx_destroy(ctx);
}
};
diff --git a/test/gtest/test_tle_udp_event.h b/test/gtest/test_tle_udp_event.h
index 4d66fb6..6aafebb 100644
--- a/test/gtest/test_tle_udp_event.h
+++ b/test/gtest/test_tle_udp_event.h
@@ -18,7 +18,7 @@
#include <gtest/gtest.h>
#include <rte_errno.h>
-#include <tle_udp_impl.h>
+#include <tle_ctx.h>
#include <tle_event.h>
struct event_state_active {
diff --git a/test/gtest/test_tle_udp_stream.cpp b/test/gtest/test_tle_udp_stream.cpp
index 22a1b44..44a8a65 100644
--- a/test/gtest/test_tle_udp_stream.cpp
+++ b/test/gtest/test_tle_udp_stream.cpp
@@ -14,15 +14,14 @@
*/
#include "test_tle_udp_stream.h"
+#include <arpa/inet.h>
TEST_F(test_tle_udp_stream, stream_test_open)
{
stream = tle_udp_stream_open(ctx,
(const struct tle_udp_stream_param *)&stream_prm);
EXPECT_NE(stream, nullptr);
- ret = tle_udp_stream_close(stream);
-
- EXPECT_EQ(ret, 0);
+ streams.push_back(stream);
}
TEST_F(test_tle_udp_stream, stream_test_open_nullctx)
@@ -60,8 +59,20 @@ TEST_F(test_tle_udp_stream, stream_test_open_close_open_close)
(const struct tle_udp_stream_param*)&stream_prm);
EXPECT_NE(stream, nullptr);
- ret = tle_udp_stream_close(stream);
- EXPECT_EQ(ret, 0);
+ streams.push_back(stream);
+}
+
+TEST_F(test_tle_udp_stream, stream_test_open_duplicate)
+{
+ stream = tle_udp_stream_open(ctx,
+ (const struct tle_udp_stream_param *)&stream_prm);
+ EXPECT_NE(stream, nullptr);
+ streams.push_back(stream);
+
+ stream = tle_udp_stream_open(ctx,
+ (const struct tle_udp_stream_param *)&stream_prm);
+ EXPECT_EQ(stream, nullptr);
+ EXPECT_EQ(rte_errno, EEXIST);
}
TEST_F(test_tle_udp_stream, stream_test_close)
@@ -80,7 +91,6 @@ TEST_F(test_tle_udp_stream, stream_test_close_null)
EXPECT_EQ(ret, -EINVAL);
}
-
TEST_F(test_tle_udp_stream, stream_test_close_already)
{
stream = tle_udp_stream_open(ctx,
@@ -92,6 +102,7 @@ TEST_F(test_tle_udp_stream, stream_test_close_already)
ret = tle_udp_stream_close(stream);
EXPECT_NE(ret, 0);
+ EXPECT_EQ(ret, -EINVAL);
}
TEST_F(test_tle_udp_stream, stream_get_param)
@@ -101,6 +112,7 @@ TEST_F(test_tle_udp_stream, stream_get_param)
stream = tle_udp_stream_open(ctx,
(const struct tle_udp_stream_param *)&stream_prm);
EXPECT_NE(stream, nullptr);
+ streams.push_back(stream);
ret = tle_udp_stream_get_param(stream,&prm);
EXPECT_EQ(ret, 0);
@@ -113,6 +125,7 @@ TEST_F(test_tle_udp_stream, stream_get_param_streamnull)
stream = tle_udp_stream_open(ctx,
(const struct tle_udp_stream_param *)&stream_prm);
EXPECT_NE(stream, nullptr);
+ streams.push_back(stream);
ret = tle_udp_stream_get_param(nullptr, &prm);
EXPECT_EQ(ret, -EINVAL);
@@ -125,10 +138,59 @@ TEST_F(test_tle_udp_stream, stream_get_param_prmnull)
stream = tle_udp_stream_open(ctx,
(const struct tle_udp_stream_param *)&stream_prm);
EXPECT_NE(stream, nullptr);
+ streams.push_back(stream);
ret = tle_udp_stream_get_param(stream, nullptr);
EXPECT_EQ(ret, -EINVAL);
}
-
-
+TEST_F(test_tle_udp_stream_max, stream_test_open_max)
+{
+ int i, j, cnt;
+ struct in_addr src_s;
+ struct in_addr dst_s;
+ int dst_port = 32678;
+ struct sockaddr_in *l_ipv4;
+ struct sockaddr_in *r_ipv4;
+
+ /* Set fields that will not change in sockaddr structures */
+ inet_pton(AF_INET, base_l_ipv4, &src_s);
+ l_ipv4 = (struct sockaddr_in *) &stream_prm.local_addr;
+ l_ipv4->sin_family = AF_INET;
+ l_ipv4->sin_port = htons(0);
+
+ inet_pton(AF_INET, base_r_ipv4, &dst_s);
+ r_ipv4 = (struct sockaddr_in *) &stream_prm.remote_addr;
+ r_ipv4->sin_family = AF_INET;
+
+ for(i = 0, cnt = 0; i < devs.size(); i++) {
+ /* Get base IPv4 address and increment it if needed for
+ * stream source address;
+ * Incrementing only highest octet
+ */
+
+ l_ipv4->sin_addr.s_addr = src_s.s_addr + i;
+
+ for(j = 0; j < nb_streams; j++, cnt++) {
+ /* Get base IPv4 address and increment it if needed for
+ * stream destination address
+ */
+ r_ipv4->sin_port = htons(dst_port + j);
+ r_ipv4->sin_addr.s_addr =
+ htonl(ntohl(dst_s.s_addr) + j);
+
+ stream = tle_udp_stream_open(ctx,
+ (const struct tle_udp_stream_param *)
+ &stream_prm);
+
+ if (cnt < MAX_STREAMS) {
+ EXPECT_EQ(rte_errno, 0);
+ ASSERT_NE(stream, nullptr);
+ streams.push_back(stream);
+ } else if (cnt >= MAX_STREAMS) {
+ EXPECT_EQ(stream, nullptr);
+ EXPECT_EQ(rte_errno, ENFILE);
+ }
+ }
+ }
+}
diff --git a/test/gtest/test_tle_udp_stream.h b/test/gtest/test_tle_udp_stream.h
index d0256c3..582eaea 100644
--- a/test/gtest/test_tle_udp_stream.h
+++ b/test/gtest/test_tle_udp_stream.h
@@ -16,81 +16,88 @@
#ifndef TEST_TLE_UDP_STREAM_H_
#define TEST_TLE_UDP_STREAM_H_
#include <iostream>
+#include <algorithm>
+#include <string>
#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <rte_errno.h>
-#include <tle_udp_impl.h>
+#include <tle_udp.h>
#include <tle_event.h>
-int
-dummy_lookup4(void *opaque, const struct in_addr *addr,
- struct tle_udp_dest *res)
-{
- RTE_SET_USED(opaque);
- RTE_SET_USED(addr);
- RTE_SET_USED(res);
- return -ENOENT;
-}
+#include "test_common.h"
-int
-dummy_lookup6(void *opaque, const struct in6_addr *addr,
- struct tle_udp_dest *res)
-{
- RTE_SET_USED(opaque);
- RTE_SET_USED(addr);
- RTE_SET_USED(res);
- return -ENOENT;
-}
+#define MAX_STREAMS 0xFFFF
+#define MAX_STREAM_RBUFS 0x100
+#define MAX_STREAM_SBUFS 0x100
+#define RX_OFFLOAD 0x100
+#define TX_OFFLOAD 0x100
+
+using namespace std;
-struct tle_udp_ctx_param ctx_prm_tmpl = {
+struct tle_ctx_param ctx_prm_tmpl = {
.socket_id = SOCKET_ID_ANY,
- .max_streams = 0x10,
- .max_stream_rbufs = 0x100,
- .max_stream_sbufs = 0x100
+ .proto = TLE_PROTO_UDP,
+ .max_streams = MAX_STREAMS,
+ .max_stream_rbufs = MAX_STREAM_RBUFS,
+ .max_stream_sbufs = MAX_STREAM_SBUFS
};
-struct tle_udp_dev_param dev_prm_tmpl = {
- .rx_offload = 0x100,
- .tx_offload = 0x100
+struct tle_dev_param dev_prm_tmpl = {
+ .rx_offload = RX_OFFLOAD,
+ .tx_offload = TX_OFFLOAD
};
class test_tle_udp_stream: public ::testing::Test {
public:
- void setup_dev_prm(struct tle_udp_dev_param *,
+ void setup_dev_prm(struct tle_dev_param *,
char const *, char const *);
- struct tle_udp_ctx *setup_ctx(struct tle_udp_ctx_param *prm);
- struct tle_udp_dev *setup_dev(struct tle_udp_ctx *ctx,
- struct tle_udp_dev_param *dev_prm);
+ struct tle_ctx *setup_ctx(struct tle_ctx_param *prm);
+ struct tle_dev *setup_dev(struct tle_ctx *ctx,
+ struct tle_dev_param *dev_prm);
struct tle_evq *setup_event();
virtual void SetUp(void)
{
- char const *ipv4_laddr = "192.168.0.1";
- char const *ipv4_raddr = "192.168.0.2";
+ char const *ipv4_laddr = "192.0.0.1";
+ char const *ipv4_raddr = "10.0.0.1";
char const *ipv6 = "fe80::21e:67ff:fec2:2568";
- struct tle_udp_ctx_param cprm;
+ struct tle_ctx_param cprm;
+ port = 10000;
ctx = nullptr;
dev = nullptr;
stream = nullptr;
/* Setup Context */
cprm = ctx_prm_tmpl;
+ cprm.max_streams = 0xA;
cprm.lookup4 = dummy_lookup4;
cprm.lookup6 = dummy_lookup6;
ctx = setup_ctx(&cprm);
+ ASSERT_NE(ctx, nullptr);
+
/* Setup Dev */
memset(&dev_prm, 0, sizeof(dev_prm));
setup_dev_prm(&dev_prm, ipv4_laddr, ipv6);
dev = setup_dev(ctx, &dev_prm);
+ ASSERT_NE(dev, nullptr);
/* Stream Param & Event param */
memset(&stream_prm, 0, sizeof(struct tle_udp_stream_param));
- inet_pton(AF_INET, ipv4_laddr, &stream_prm.local_addr);
- inet_pton(AF_INET, ipv4_raddr, &stream_prm.remote_addr);
- stream_prm.local_addr.ss_family = AF_INET;
- stream_prm.remote_addr.ss_family = AF_INET;
+
+ ip4_addr = (struct sockaddr_in *) &stream_prm.local_addr;
+ ip4_addr->sin_family = AF_INET;
+ ip4_addr->sin_port = htons(port);
+ ip4_addr->sin_addr.s_addr = inet_addr(ipv4_laddr);
+
+ ip4_addr = (struct sockaddr_in *) &stream_prm.remote_addr;
+ ip4_addr->sin_family = AF_INET;
+ ip4_addr->sin_port = htons(port);
+ ip4_addr->sin_addr.s_addr = inet_addr(ipv4_raddr);
+
stream_prm.recv_ev = tle_event_alloc(setup_event(), nullptr);
stream_prm.send_ev = tle_event_alloc(setup_event(), nullptr);
}
@@ -98,22 +105,29 @@ public:
virtual void TearDown(void)
{
ret = 0;
- tle_udp_stream_close(stream);
- tle_udp_del_dev(dev);
- tle_udp_destroy(ctx);
+ for (auto s : streams)
+ tle_udp_stream_close(s);
+
+ tle_del_dev(dev);
+ tle_ctx_destroy(ctx);
}
int ret;
- struct tle_udp_ctx *ctx;
- struct tle_udp_dev *dev;
- struct tle_udp_stream *stream;
-
- struct tle_udp_ctx_param ctx_prm;
- struct tle_udp_dev_param dev_prm;
+ int port;
+ struct tle_ctx *ctx;
+ struct tle_dev *dev;
+ struct tle_stream *stream;
+ struct tle_ctx_param ctx_prm;
+ struct tle_dev_param dev_prm;
struct tle_udp_stream_param stream_prm;
+ struct sockaddr_in *ip4_addr;
+
+ vector<tle_stream *> streams;
};
-struct tle_evq *test_tle_udp_stream::setup_event() {
+struct tle_evq *
+test_tle_udp_stream::setup_event()
+{
int32_t socket_id;
uint32_t max_events;
struct tle_evq_param evq_params;
@@ -129,32 +143,98 @@ struct tle_evq *test_tle_udp_stream::setup_event() {
return evq;
}
-struct tle_udp_ctx
-*test_tle_udp_stream::setup_ctx(struct tle_udp_ctx_param *prm) {
- struct tle_udp_ctx *ctx;
+struct tle_ctx
+*test_tle_udp_stream::setup_ctx(struct tle_ctx_param *prm)
+{
+ struct tle_ctx *ctx;
- ctx = tle_udp_create(prm);
+ ctx = tle_ctx_create(prm);
return ctx;
}
-struct tle_udp_dev
-*test_tle_udp_stream::setup_dev(struct tle_udp_ctx *ctx,
- struct tle_udp_dev_param *dev_prm) {
-
- struct tle_udp_dev *dev;
+struct tle_dev
+*test_tle_udp_stream::setup_dev(struct tle_ctx *ctx,
+ struct tle_dev_param *dev_prm)
+{
+ struct tle_dev *dev;
- dev = tle_udp_add_dev(ctx, dev_prm);
+ dev = tle_add_dev(ctx, dev_prm);
return dev;
}
-void test_tle_udp_stream::setup_dev_prm(struct tle_udp_dev_param *dev_prm,
- char const *ipv4, char const *ipv6) {
-
+void
+test_tle_udp_stream::setup_dev_prm(struct tle_dev_param *dev_prm,
+ char const *ipv4, char const *ipv6)
+{
inet_pton(AF_INET, ipv4, &dev_prm->local_addr4);
inet_pton(AF_INET6, ipv6, &dev_prm->local_addr6);
}
+/* Fixture for max number of streams on single ctx + multiple devices */
+class test_tle_udp_stream_max: public ::test_tle_udp_stream {
+public:
+
+ virtual void SetUp(void)
+ {
+ /* Create enough devices and streams to exceed
+ * MAX_STREAMS on ctx
+ */
+ nb_devs = 10;
+ nb_streams = 6554;
+
+ in_addr_t src;
+ string ssrc;
+
+ memset(&ctx_prm, 0, sizeof(ctx_prm));
+ ctx_prm = ctx_prm_tmpl;
+ ctx_prm.lookup4 = dummy_lookup4;
+ ctx_prm.lookup6 = dummy_lookup6;
+ ctx = setup_ctx(&ctx_prm);
+ ASSERT_NE(ctx, (void *)NULL);
+
+ memset(&dev_prm, 0, sizeof(dev_prm));
+ setup_dev_prm(&dev_prm, base_l_ipv4, base_l_ipv6);
+
+ memset(&stream_prm, 0, sizeof(struct tle_udp_stream_param));
+ stream_prm.recv_ev = tle_event_alloc(setup_event(), nullptr);
+ stream_prm.send_ev = tle_event_alloc(setup_event(), nullptr);
+
+ for (i = 0; i < nb_devs; i++) {
+ ssrc = inet_ntoa(dev_prm.local_addr4);
+
+ dev = setup_dev(ctx, &dev_prm);
+ ASSERT_NE(dev, (void *)NULL);
+ devs.push_back(dev);
+
+ /* Modify base IP addresses for next loops */
+ src = dev_prm.local_addr4.s_addr;
+ src += 1;
+ dev_prm.local_addr4.s_addr = src;
+ }
+ }
+
+ virtual void TearDown(void)
+ {
+ for (auto s : streams)
+ tle_udp_stream_close(s);
+
+ for (auto d : devs)
+ tle_del_dev(d);
+
+ tle_ctx_destroy(ctx);
+ }
+
+ int i;
+ int nb_devs;
+ int nb_streams;
+ char const *base_l_ipv4 = "10.0.0.1";
+ char const *base_r_ipv4 = "190.0.0.1";
+ char const *base_l_ipv6 = "2000::1";
+ vector<tle_dev *> devs;
+ vector<tle_stream *> streams;
+};
+
#endif /* TEST_TLE_UDP_STREAM_H_ */
diff --git a/test/gtest/test_tle_udp_stream_gen.cpp b/test/gtest/test_tle_udp_stream_gen.cpp
new file mode 100644
index 0000000..0f60b09
--- /dev/null
+++ b/test/gtest/test_tle_udp_stream_gen.cpp
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test_tle_udp_stream_gen.h"
+
+TEST_P(tle_rx_enobufs, enobufs_test)
+{
+ int j, pkt_cnt = 0, enobufs_cnt = 0;
+ uint16_t nb_rx, nb_rx_bulk;
+ struct rte_mbuf *m[BURST_SIZE];
+ struct rte_mbuf *rp[BURST_SIZE];
+ int rc[BURST_SIZE];
+
+ /* Receive packets until we reach end on pcap file*/
+ do {
+ memset(rc, 0, sizeof(int) * BURST_SIZE);
+ nb_rx = rte_eth_rx_burst(portid, 0, m, BURST_SIZE);
+ pkt_cnt += nb_rx;
+ for(auto &d: tp.devs){
+ nb_rx_bulk = tle_udp_rx_bulk(d.ptr, m, rp, rc, nb_rx);
+ for(j = 0; j < BURST_SIZE; j++) {
+ if(rc[j] == ENOBUFS) {
+ enobufs_cnt++;
+ }
+ }
+ d.act_pkts_bulk_rx += nb_rx_bulk;
+ }
+ } while (nb_rx > 0);
+
+ /*
+ * Verify results - number of rx packets per dev and stream
+ * and packets dropped due to ENOBUFS
+ */
+
+ for(auto &d: tp.devs) {
+ EXPECT_EQ(d.act_pkts_bulk_rx, d.exp_pkts_bulk_rx);
+ EXPECT_EQ(enobufs_cnt, pkt_cnt - d.act_pkts_bulk_rx);
+ }
+}
+/*
+ * TODO: Obviously this way of defining test scenarios is terrible.
+ * Need to move to JSON files in future and parse from external file.
+ * Currently first commented out entry is an example of what values should be
+ * inserted into certain fields
+ * */
+INSTANTIATE_TEST_CASE_P(enobufs_test, tle_rx_enobufs, testing::Values(
+/* test_str example */
+/* {
+ "Description",
+ Devices configs below
+ {
+ {"Dev local IPv4", "Dev local IPv6",
+ RX_OFFLOAD, TX_OFFLOAD,
+ Exp. nb. of rx pkts on device,
+ Exp. nb. of tx pkts on device,
+ Exp. nb. of total ENOENT pkts on device,
+ },
+ },
+ Streams config on device below
+ {
+ {local port, remote port, "local ip", "remote ip",
+ exp. nb. of rx. pkts, exp. nb. of tx. pkts},
+ },
+ Pkts to generate with scapy to pcap file
+ {
+ {"Src IP", "Dst IP",
+ Src port, Dst port,
+ nb of pkts,
+ l3 chksum, l4 chksum, fragment?},
+ }
+}, */
+test_str
+{
+ "IPv4 - 1 dev 1 stream, only correct pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD,
+ CTX_MAX_RBUFS - 1, 0, 0}
+ },
+ {
+ {AF_INET, 10001, 10002, "10.0.0.1", "10.0.0.2", 0, 0},
+ },
+ {
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10002, 10001, 1000, 0, 0, 0},
+ }
+},
+test_str
+{
+ "IPv4 - 1 dev 1 stream, only correct pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD,
+ CTX_MAX_RBUFS - 1, 0, 0, 0}
+ },
+ {
+ {AF_INET6, 10001, 10002, "2001::1000", "2001::2000", 0, 0},
+ },
+ {
+ {AF_INET6, "2001::2000", "2001::1000", 10002, 10001, 1000, 0, 0, 0},
+ }
+}
+));
+
+TEST_P(tle_rx_test, test)
+{
+ int j;
+ uint16_t nb_rx, nb_rx_bulk, nb_str_rx;
+ struct rte_mbuf *m[BURST_SIZE];
+ struct rte_mbuf *n[BURST_SIZE];
+ struct rte_mbuf *rp[BURST_SIZE];
+ int rc[BURST_SIZE];
+
+ /* Receive packets until we reach end on pcap file*/
+ do {
+ nb_rx = rte_eth_rx_burst(portid, 0, m, BURST_SIZE);
+ for(auto &d: tp.devs) {
+ memset(rc, 0, sizeof(int) * BURST_SIZE);
+ nb_rx_bulk = tle_udp_rx_bulk(d.ptr, m, rp, rc, nb_rx);
+ d.act_pkts_bulk_rx += nb_rx_bulk;
+ for(j = 0; j < BURST_SIZE; j++) {
+ if(rc[j] == ENOENT)
+ d.act_pkts_enoent += 1;
+ }
+ }
+
+ for(auto &s: tp.streams) {
+ nb_str_rx = tle_udp_stream_recv(s.ptr, n, BURST_SIZE);
+ s.act_pkts_rx += nb_str_rx;
+ }
+ } while (nb_rx > 0);
+
+
+ /*
+ * Verify results - number of rx packets per dev and stream.
+ */
+ for(auto &d: tp.devs) {
+ EXPECT_EQ(d.act_pkts_bulk_rx, d.exp_pkts_bulk_rx);
+ EXPECT_EQ(d.act_pkts_enoent, d.exp_pkts_enoent);
+ }
+
+ for(auto &s: tp.streams) {
+ EXPECT_EQ(s.act_pkts_rx, s.exp_pkts_rx);
+ }
+}
+INSTANTIATE_TEST_CASE_P(rx_recv, tle_rx_test, testing::Values(
+test_str
+{
+ "IPv4 - 1 dev 1 stream, only correct pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 10, 0, 0},
+ },
+ {
+ {AF_INET, 10001, 10002, "10.0.0.1", "10.0.0.2", 10, 0},
+ },
+ {
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10002, 10001, 10, 0, 0, 0},
+ }
+},
+
+test_str
+{
+ "IPv4 - 1 dev 1 stream, only incorrect pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 0, 0, 40},
+ },
+ {
+ {AF_INET, 10001, 10002, "10.0.0.1", "10.0.0.2", 0, 0},
+ },
+ {
+ {AF_INET, "20.0.0.2", "10.0.0.1", 10002, 10001, 10, 0, 0, 0},
+ {AF_INET, "10.0.0.2", "20.0.0.1", 10002, 10001, 10, 0, 0, 0},
+ {AF_INET, "10.0.0.2", "10.0.0.1", 20002, 10001, 10, 0, 0, 0},
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10002, 20001, 10, 0, 0, 0},
+ }
+},
+
+test_str
+{
+ "IPv4 - 1 dev with 1 stream, only correct pkts but incorrect chksum",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 30, 0, 0}
+ },
+ {
+ {AF_INET, 10001, 10002, "10.0.0.1", "10.0.0.2", 0, 0},
+ },
+ {
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10002, 10001, 10, 1, 0, 0},
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10002, 10001, 10, 0, 1, 0},
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10002, 10001, 10, 1, 1, 0},
+ }
+},
+
+test_str
+{
+ "IPv6 - 1 dev with 1 stream, only correct pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 10, 0, 0}
+ },
+ {
+ {AF_INET6, 10001, 10002, "2001::1000", "2001::2000", 10, 0},
+ },
+ {
+ {AF_INET6, "2001::2000", "2001::1000", 10002, 10001, 10, 0, 0, 0},
+ }
+},
+
+test_str
+{
+ "IPv6 - 1 dev with 1 stream, only incorrect pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 0, 0, 40},
+ },
+ {
+ {AF_INET6, 10001, 10002, "2001::1000", "2001::2000", 0, 0},
+ },
+ {
+ {AF_INET6, "3001::2000", "2001::1000", 10002, 10001, 10, 0, 0, 0},
+ {AF_INET6, "2001::3000", "2001::1000", 10002, 10001, 10, 0, 0, 0},
+ {AF_INET6, "2001::2000", "2001::1000", 30002, 10001, 10, 0, 0, 0},
+ {AF_INET6, "2001::2000", "2001::1000", 10002, 30001, 10, 0, 0, 0},
+ }
+},
+
+test_str
+{
+ "IPv6 - 1 dev with 1 stream, only correct pkts but incorrect chksum",
+ /*
+ * Note: one of streams will be received as IPv6 does not have
+ * checksum field by default.
+ */
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 30, 0, 0}
+ },
+ {
+ {AF_INET6, 10001, 10002, "2001::1000", "2001::2000", 10, 0},
+ },
+ {
+ {AF_INET6, "2001::2000", "2001::1000", 10002, 10001, 10, 1, 0, 0},
+ {AF_INET6, "2001::2000", "2001::1000", 10002, 10001, 10, 0, 1, 0},
+ {AF_INET6, "2001::2000", "2001::1000", 10002, 10001, 10, 1, 1, 0},
+ }
+},
+
+test_str
+{
+ /* Multiple streams, multiple correct pkt streams, mixed IPv4 & IPv6;
+ * 3 dev, 3 stream per dev, only correct pkts */
+ "Mixed IPv4+IPv6; Multiple devs with multiple correct streams",
+ {
+ {"10.0.0.1", "2001::1000",RX_NO_OFFLOAD, TX_NO_OFFLOAD, 300, 0, 600},
+ {"20.0.0.1", "2002::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 300, 0, 600},
+ {"30.0.0.1", "2003::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 300, 0, 600},
+ },
+ {
+ {AF_INET, 10001, 10011, "10.0.0.1", "10.0.0.2", 100, 0},
+ {AF_INET, 10002, 10012, "10.0.0.1", "10.0.0.3", 100, 0},
+ {AF_INET6, 10003, 10013, "2001::1000", "2001::4000", 100, 0},
+ {AF_INET, 20001, 20011, "20.0.0.1", "20.0.0.2", 100, 0},
+ {AF_INET6, 20002, 20012, "2002::1000", "2002::3000", 100, 0},
+ {AF_INET6, 20003, 20013, "2002::1000", "2002::4000", 100, 0},
+ {AF_INET, 20001, 20011, "30.0.0.1", "30.0.0.2", 100, 0},
+ {AF_INET6, 20002, 20012, "2003::1000", "2003::3000", 100, 0},
+ {AF_INET6, 20003, 20013, "2003::1000", "2003::4000", 100, 0}
+ },
+ {
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10011, 10001, 100, 0, 0, 0},
+ {AF_INET, "10.0.0.3", "10.0.0.1", 10012, 10002, 100, 0, 0, 0},
+ {AF_INET, "20.0.0.2", "20.0.0.1", 20011, 20001, 100, 0, 0, 0},
+ {AF_INET, "30.0.0.2", "30.0.0.1", 20011, 20001, 100, 0, 0, 0},
+ {AF_INET6, "2001::4000", "2001::1000", 10013, 10003, 100, 0, 0, 0},
+ {AF_INET6, "2002::3000", "2002::1000", 20012, 20002, 100, 0, 0, 0},
+ {AF_INET6, "2002::4000", "2002::1000", 20013, 20003, 100, 0, 0, 0},
+ {AF_INET6, "2003::3000", "2003::1000", 20012, 20002, 100, 0, 0, 0},
+ {AF_INET6, "2003::4000", "2003::1000", 20013, 20003, 100, 0, 0, 0},
+ }
+}
+));
+
+TEST_P(tle_tx_test, tx_send)
+{
+ int i, j, s, pkts_to_send;
+ uint16_t nb_tx, nb_tx_bulk, nb_str_tx;
+ struct rte_mbuf *m[BURST_SIZE];
+ struct rte_mbuf *n[BURST_SIZE];
+ int rc[BURST_SIZE];
+ struct sockaddr_storage dest;
+ uint8_t *plaintext;
+ unsigned plaintext_len;
+ unsigned plaintext_pad_len;
+ char text[]="DEADBEEF";
+
+ for(auto &sg: tp.gen_streams) {
+
+ /* Find from which stream we will be sending - save the pointer and
+ * index number for later TX counter validation */
+ for(s = 0; s < tp.streams.size(); s++) {
+ auto tmp = tp.streams[s];
+ if(sg.dst_ip.compare(tmp.l_ip) == 0 && sg.dst_port == tmp.l_port) {
+ stream = tmp.ptr;
+ break;
+ }
+ }
+
+ /* Prepare sockaddr for sending */
+ memset(&dest, 0, sizeof(dest));
+ if (sg.family == AF_INET) {
+ ((sockaddr_in *) &dest)->sin_family = AF_INET;
+ ((sockaddr_in *) &dest)->sin_port = htons(sg.src_port);
+ inet_pton(AF_INET, sg.src_ip.c_str(),
+ &((sockaddr_in *) &dest)->sin_addr);
+ } else if (sg.family == AF_INET6) {
+ ((sockaddr_in6 *) &dest)->sin6_family = AF_INET6;
+ ((sockaddr_in6 *) &dest)->sin6_port = htons(sg.src_port);
+ inet_pton(AF_INET6, sg.src_ip.c_str(),
+ &((sockaddr_in6 *) &dest)->sin6_addr);
+ }
+
+ nb_str_tx = 0;
+ /* Send all packets to stream*/
+ for(i = 0; i < sg.nb_pkts; i += nb_str_tx) {
+ pkts_to_send = (sg.nb_pkts - i < BURST_SIZE) ?
+ (sg.nb_pkts - i) : BURST_SIZE;
+
+ /* Allocate Mbufs */
+ for(j = 0; j < pkts_to_send; j++) {
+ m[j] = rte_pktmbuf_alloc(mbuf_pool);
+ ASSERT_NE(m[j], nullptr);
+
+ memset(rte_pktmbuf_mtod(m[j], uint8_t *), 0,
+ rte_pktmbuf_tailroom(m[j]));
+ plaintext = (uint8_t *)rte_pktmbuf_append(m[j],
+ sizeof(text));
+ memcpy(rte_pktmbuf_mtod(m[j], uint8_t *), &text, sizeof(text));
+ }
+
+ nb_str_tx = tle_udp_stream_send(stream, m, pkts_to_send,
+ reinterpret_cast<struct sockaddr*>(&dest));
+ ASSERT_GE(nb_str_tx, 0);
+ if(nb_str_tx == 0) {
+ for(j = 0; j < pkts_to_send; j++) {
+ rte_pktmbuf_free(m[j]);
+ }
+ nb_str_tx = pkts_to_send;
+ continue;
+ }
+ tp.streams[s].act_pkts_tx += nb_str_tx;
+ }
+ }
+
+ /* Send out packets from devices */
+ for(auto &d: tp.devs) {
+ nb_tx_bulk = 0;
+ do {
+ nb_tx_bulk = tle_udp_tx_bulk(d.ptr, n, BURST_SIZE);
+ ASSERT_GE(nb_str_tx, 0);
+ d.act_pkts_bulk_tx += nb_tx_bulk;
+ nb_tx = rte_eth_tx_burst(portid, 0, n, nb_tx_bulk);
+ ASSERT_GE(nb_str_tx, 0);
+ } while (nb_tx_bulk > 0);
+ }
+
+ /*
+ * Verify results - number of rx packets per dev and stream.
+ */
+ for(auto &d: tp.devs) {
+ EXPECT_EQ(d.act_pkts_bulk_tx, d.exp_pkts_bulk_tx);
+ EXPECT_EQ(d.act_pkts_enoent, d.exp_pkts_enoent);
+ }
+
+ for(auto &s: tp.streams) {
+ EXPECT_EQ(s.act_pkts_tx, s.exp_pkts_tx);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(test, tle_tx_test, testing::Values(
+test_str
+{
+ "IPv4 - 1 dev 1 stream, only correct pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 0, 100, 0},
+ },
+ {
+ {AF_INET, 10001, 10002, "10.0.0.1", "10.0.0.2", 0, 100},
+ },
+ {
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10002, 10001, 100, 0, 0, 0},
+ }
+},
+test_str
+{
+ "IPv6 - 1 dev 1 stream, only correct pkts",
+ {
+ {"10.0.0.1", "2001::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 0, 100, 0},
+ },
+ {
+ {AF_INET6, 10001, 10002, "2001::1000", "2001::2000", 0, 100},
+ },
+ {
+ {AF_INET6, "2001::2000", "2001::1000", 10002, 10001, 100, 0, 0, 0},
+ }
+},
+test_str
+{
+ /* Multiple streams, mixed IPv4 & IPv6; */
+ "Mixed IPv4+IPv6; Multiple devs with multiple correct streams",
+ {
+ {"10.0.0.1", "2001::1000",RX_NO_OFFLOAD, TX_NO_OFFLOAD, 0, 300, 0},
+ {"20.0.0.1", "2002::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 0, 300, 0},
+ {"30.0.0.1", "2003::1000", RX_NO_OFFLOAD, TX_NO_OFFLOAD, 0, 300, 0},
+ },
+ {
+ {AF_INET, 10001, 10011, "10.0.0.1", "10.0.0.2", 0, 100},
+ {AF_INET, 10002, 10012, "10.0.0.1", "10.0.0.3", 0, 100},
+ {AF_INET6, 10003, 10013, "2001::1000", "2001::4000", 0, 100},
+ {AF_INET, 20001, 20011, "20.0.0.1", "20.0.0.2", 0, 100},
+ {AF_INET6, 20002, 20012, "2002::1000", "2002::3000", 0, 100},
+ {AF_INET6, 20003, 20013, "2002::1000", "2002::4000", 0, 100},
+ {AF_INET, 20001, 20011, "30.0.0.1", "30.0.0.2", 0, 100},
+ {AF_INET6, 20002, 20012, "2003::1000", "2003::3000", 0, 100},
+ {AF_INET6, 20003, 20013, "2003::1000", "2003::4000", 0, 100}
+ },
+ {
+ {AF_INET, "10.0.0.2", "10.0.0.1", 10011, 10001, 100, 0, 0, 0},
+ {AF_INET, "10.0.0.3", "10.0.0.1", 10012, 10002, 100, 0, 0, 0},
+ {AF_INET, "20.0.0.2", "20.0.0.1", 20011, 20001, 100, 0, 0, 0},
+ {AF_INET, "30.0.0.2", "30.0.0.1", 20011, 20001, 100, 0, 0, 0},
+ {AF_INET6, "2001::4000", "2001::1000", 10013, 10003, 100, 0, 0, 0},
+ {AF_INET6, "2002::3000", "2002::1000", 20012, 20002, 100, 0, 0, 0},
+ {AF_INET6, "2002::4000", "2002::1000", 20013, 20003, 100, 0, 0, 0},
+ {AF_INET6, "2003::3000", "2003::1000", 20012, 20002, 100, 0, 0, 0},
+ {AF_INET6, "2003::4000", "2003::1000", 20013, 20003, 100, 0, 0, 0},
+ }
+}
+));
diff --git a/test/gtest/test_tle_udp_stream_gen.h b/test/gtest/test_tle_udp_stream_gen.h
new file mode 100644
index 0000000..294e37c
--- /dev/null
+++ b/test/gtest/test_tle_udp_stream_gen.h
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_TLE_UDP_STREAM_GEN_H_
+#define TEST_TLE_UDP_STREAM_GEN_H_
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <map>
+#include <string>
+#include <algorithm>
+#include <arpa/inet.h>
+#include <netinet/ip6.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <gtest/gtest.h>
+
+#include <rte_version.h>
+
+#include <tle_udp.h>
+#include <tle_event.h>
+
+#include "test_common.h"
+
+#define RX_NO_OFFLOAD 0
+#define TX_NO_OFFLOAD 0
+#define CTX_MAX_RBUFS 0x100
+#define CTX_MAX_SBUFS 0x100
+
+#define RX_PCAP "rx_pcap.cap"
+#define TX_PCAP "tx_pcap.cap"
+
+/*
+ * Check DPDK version:
+ * Previous "eth_pcap" was changed to "net_pcap" after DPDK 16.07.
+ * Use correct vdev name depending on version.
+ */
+#if (RTE_VERSION_NUM(16, 7, 0, 0) < \
+ RTE_VERSION_NUM(RTE_VER_YEAR, RTE_VER_MONTH, 0, 0))
+ #define VDEV_NAME "net_pcap0"
+#else
+ #define VDEV_NAME "eth_pcap0"
+#endif
+
+using namespace std;
+
+extern struct rte_mempool *mbuf_pool;
+
+/* Dummy lookup functions, TX operations are not performed in these tests */
+
+static int
+lookup4_function(void *opaque, const struct in_addr *addr, struct tle_dest *res)
+{
+ struct in_addr route;
+ struct ether_hdr *eth;
+ struct ipv4_hdr *ip4h;
+ auto routes = static_cast<map<string, tle_dev *> *>(opaque);
+
+ /* Check all routes added in map for a match with dest *addr */
+ for (auto it = routes->begin(); it != routes->end(); ++it) {
+ inet_pton(AF_INET, it->first.c_str(), &route);
+
+ /* If it matches then fill *res and return with 0 code */
+ if (memcmp(&route, addr, sizeof(struct in_addr)) == 0) {
+ memset(res, 0, sizeof(*res));
+ res->dev = it->second;
+ res->mtu = 1500;
+ res->l2_len = sizeof(*eth);
+ res->l3_len = sizeof(*ip4h);
+ res->head_mp = mbuf_pool;
+ eth = (struct ether_hdr *)res->hdr;
+ eth->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+ ip4h = (struct ipv4_hdr *)(eth + 1);
+ ip4h->version_ihl = (4 << 4) |
+ (sizeof(*ip4h) / IPV4_IHL_MULTIPLIER);
+ ip4h->time_to_live = 64;
+ ip4h->next_proto_id = IPPROTO_UDP;
+ ip4h->fragment_offset = 0;
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int
+lookup6_function(void *opaque, const struct in6_addr *addr,
+ struct tle_dest *res)
+{
+ struct ether_hdr *eth;
+ struct ipv6_hdr *ip6h;
+ struct in6_addr route;
+ auto routes = static_cast<map<string, tle_dev *> *>(opaque);
+
+ /* Check all routes added in map for a match with dest *addr */
+ for (auto it = routes->begin(); it != routes->end(); ++it) {
+ inet_pton(AF_INET6, it->first.c_str(), &route);
+
+ /* If it matches then fill *res and return with 0 code */
+ if (memcmp(&route, addr, sizeof(struct in6_addr)) == 0) {
+ memset(res, 0, sizeof(*res));
+ res->dev = it->second;
+ res->mtu = 1500;
+ res->l2_len = sizeof(*eth);
+ res->l3_len = sizeof(*ip6h);
+ res->head_mp = mbuf_pool;
+ eth = (struct ether_hdr *)res->hdr;
+ eth->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+ ip6h = (struct ipv6_hdr *)(eth + 1);
+ ip6h->vtc_flow = 6 << 4;
+ ip6h->proto = IPPROTO_UDP;
+ ip6h->hop_limits = 64;
+
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/*
+ * Structures used to describe test instances:
+ * test_str - main structure for describing test case instance; contains
+ * instance description, and vectors with information about
+ * devices, streams & streams to be generated for RX/TX path.
+ * dev_s - structure describing single device; contains device addresses,
+ * checksum offload information and expected number of received /
+ * transmitted packets.
+ * packets for that device in scenario.
+ * stream_s - structure describing single stream to be created; contains
+ * information on local & remote IP's and port numbers, expected
+ * number of received and transmitted packets.
+ * stream_g - structure describing a stream which to generate via scapy script;
+ * Contains information on IP addresses and port numbers and if
+ * L3/L4 checksums should be incorrectly calculated.
+ * In future: if packet should be fragmented.
+ */
+
+struct stream_g {
+ int family;
+ string src_ip;
+ string dst_ip;
+ int src_port;
+ int dst_port;
+ int nb_pkts;
+ bool bad_chksum_l3;
+ bool bad_chksum_l4;
+ bool fragment;
+};
+
+struct stream_s {
+ int family;
+ int l_port;
+ int r_port;
+ string l_ip;
+ string r_ip;
+ int exp_pkts_rx;
+ int exp_pkts_tx;
+ int act_pkts_rx;
+ int act_pkts_tx;
+ tle_stream *ptr;
+};
+
+struct dev_s {
+ string l_ipv4;
+ string l_ipv6;
+ int rx_offload;
+ int tx_offload;
+ int exp_pkts_bulk_rx;
+ int exp_pkts_bulk_tx;
+ int exp_pkts_enoent;
+ int act_pkts_bulk_rx;
+ int act_pkts_bulk_tx;
+ int act_pkts_enoent;
+ tle_dev *ptr;
+};
+
+struct test_str {
+ string test_desc;
+ vector<dev_s> devs;
+ vector<stream_s> streams;
+ vector<stream_g> gen_streams;
+};
+
+const char *vdevargs[] = {VDEV_NAME",rx_pcap=" RX_PCAP",tx_pcap=" TX_PCAP};
+
+class test_tle_udp_gen_base : public testing::TestWithParam<test_str> {
+public:
+
+ tle_ctx *setup_ctx(void);
+ tle_dev *setup_dev(tle_ctx *ctx, uint32_t rx_offload,
+ uint32_t tx_offload, const char *local_ipv4,
+ const char *local_ipv6);
+ tle_evq *setup_evq(void);
+ tle_event *setup_event(void);
+ tle_stream *setup_stream(struct tle_ctx *ctx, int family,
+ const char *l_ip, const char *r_ip, int l_port, int r_port);
+ int setup_devices(uint8_t *portid);
+ int cleanup_devices(uint8_t portid);
+ int prepare_pcaps(string l_ip, string r_ip, int l_port, int r_port,
+ int nb_pkts, int l3_chksum, int l4_chksum, string rx_pcap_dest);
+
+ int cleanup_pcaps(const char *file);
+ int close_streams(vector<struct stream_s> streams);
+ int del_devs(vector<struct dev_s> devs);
+
+ virtual void SetUp(void)
+ {
+ nb_ports = 1;
+ tp = GetParam();
+
+ /* Usual tldk stuff below -> ctx, dev, events etc. */
+ ctx = setup_ctx();
+ ASSERT_NE(ctx, nullptr);
+
+ evq = setup_evq();
+ ASSERT_NE(evq, nullptr);
+
+ for (auto &d : tp.devs) {
+ dev = setup_dev(ctx, d.rx_offload, d.tx_offload,
+ d.l_ipv4.c_str(), d.l_ipv6.c_str());
+ ASSERT_NE(dev, nullptr);
+
+ /* Initialize counters for verifying results */
+ d.act_pkts_bulk_rx = 0;
+ d.act_pkts_bulk_tx = 0;
+ d.act_pkts_enoent = 0;
+
+ /* Save pointer to device */
+ d.ptr = dev;
+ }
+
+ for (auto &s : tp.streams) {
+ stream = setup_stream(ctx, s.family,
+ s.l_ip.c_str(), s.r_ip.c_str(),
+ s.l_port, s.r_port);
+ ASSERT_NE(stream, nullptr);
+
+ /* Initialize counters for verifying results */
+ s.act_pkts_rx = 0;
+ s.act_pkts_tx = 0;
+
+ /* Save pointer to stream */
+ s.ptr = stream;
+
+ /* Find which dev has the same address as streams
+ * local address and save destination for later use
+ * in lookup functions
+ */
+ if (s.family == AF_INET) {
+ for (auto &d : tp.devs) {
+ if (s.l_ip.compare(d.l_ipv4) == 0)
+ routes4.insert(pair<string,
+ tle_dev *>(s.r_ip,
+ d.ptr));
+ }
+ } else if (s.family == AF_INET6) {
+ for (auto &d : tp.devs) {
+ if (s.l_ip.compare(d.l_ipv6) == 0)
+ routes6.insert(pair<string,
+ tle_dev *>(s.r_ip,
+ d.ptr));
+ }
+ }
+ }
+
+ /* setup pcap/eth devices */
+ setup_devices(&portid);
+ }
+
+ virtual void TearDown(void)
+ {
+ /*
+ * Remember to shutdown & detach rte devices
+ * and clean / delete .pcap files so not to
+ * interfere with next test
+ */
+ close_streams(tp.streams);
+ del_devs(tp.devs);
+ tle_ctx_destroy(ctx);
+ cleanup_devices(portid);
+ cleanup_pcaps(RX_PCAP);
+ cleanup_pcaps(TX_PCAP);
+ }
+
+ uint8_t nb_ports;
+ uint8_t portid;
+ uint32_t socket_id;
+ uint32_t max_events;
+ struct tle_ctx *ctx;
+ struct tle_dev *dev;
+ struct tle_evq *evq;
+ struct tle_stream *stream;
+ map<string, tle_dev *> routes4;
+ map<string, tle_dev *> routes6;
+ test_str tp;
+ void *cb;
+};
+
+int
+test_tle_udp_gen_base::setup_devices(uint8_t *portid)
+{
+ /* attach + configure + start pmd device */
+ if (rte_eth_dev_attach(vdevargs[0], portid) != 0)
+ return -1;
+ cb = rte_eth_add_rx_callback(*portid, 0,
+ typen_rx_callback, nullptr);
+ if (port_init(*portid, mbuf_pool) != 0)
+ return -1;
+
+ return 0;
+}
+
+int
+test_tle_udp_gen_base::cleanup_devices(uint8_t portid)
+{
+ /* release mbufs + detach device */
+ char name[RTE_ETH_NAME_MAX_LEN];
+
+ rte_eth_dev_stop(portid);
+ rte_eth_dev_close(portid);
+ rte_eth_dev_detach(portid, name);
+
+ return 0;
+}
+
+int
+test_tle_udp_gen_base::prepare_pcaps(string l_ip, string r_ip, int l_port,
+ int r_port, int nb_pkts, int l3_chksum, int l4_chksum,
+ string rx_pcap_dest)
+{
+ string py_cmd;
+
+ /* generate pcap rx & tx files * for tests using scapy */
+ py_cmd = "python ./test/gtest/test_scapy_gen.py ";
+ py_cmd = py_cmd + " " + l_ip + " " + r_ip + " " +
+ to_string(l_port) + " " + to_string(r_port) + " " +
+ to_string(nb_pkts);
+
+ if (l3_chksum > 0)
+ py_cmd = py_cmd + " -bc3 " + to_string(l3_chksum);
+ if (l4_chksum > 0)
+ py_cmd = py_cmd + " -bc4 " + to_string(l4_chksum);
+ py_cmd = py_cmd + " " + rx_pcap_dest;
+ system(py_cmd.c_str());
+
+ return 0;
+}
+
+int
+test_tle_udp_gen_base::cleanup_pcaps(const char *file)
+{
+ if (remove(file) != 0)
+ perror("Error deleting pcap file");
+
+ return 0;
+}
+
+tle_ctx *
+test_tle_udp_gen_base::setup_ctx(void)
+{
+
+ struct tle_ctx *ctx;
+ struct tle_ctx_param ctx_prm;
+
+ memset(&ctx_prm, 0, sizeof(ctx_prm));
+ ctx_prm.socket_id = SOCKET_ID_ANY;
+ ctx_prm.max_streams = 0x10;
+ ctx_prm.max_stream_rbufs = CTX_MAX_RBUFS;
+ ctx_prm.max_stream_sbufs = CTX_MAX_SBUFS;
+ ctx_prm.lookup4 = lookup4_function;
+ ctx_prm.lookup6 = lookup6_function;
+ ctx_prm.lookup4_data = &routes4;
+ ctx_prm.lookup6_data = &routes6;
+
+ ctx = tle_ctx_create(&ctx_prm);
+
+ return ctx;
+}
+
+struct tle_dev *
+test_tle_udp_gen_base::setup_dev(struct tle_ctx *ctx, uint32_t rx_offload,
+ uint32_t tx_offload, const char *l_ipv4, const char *l_ipv6)
+{
+ struct tle_dev *dev;
+ struct tle_dev_param dev_prm;
+
+ memset(&dev_prm, 0, sizeof(dev_prm));
+ dev_prm.rx_offload = RX_NO_OFFLOAD;
+ dev_prm.tx_offload = TX_NO_OFFLOAD;
+ if (l_ipv4 != NULL)
+ inet_pton(AF_INET, l_ipv4, &(dev_prm).local_addr4);
+ if (l_ipv6 != NULL)
+ inet_pton(AF_INET6, l_ipv6, &(dev_prm).local_addr6);
+
+ dev = tle_add_dev(ctx, &dev_prm);
+
+ return dev;
+}
+
+struct tle_evq *
+test_tle_udp_gen_base::setup_evq()
+{
+ uint32_t socket_id;
+ uint32_t max_events;
+ struct tle_evq_param evq_params;
+ struct tle_evq *evq;
+
+ socket_id = SOCKET_ID_ANY;
+ max_events = 10;
+ memset(&evq_params, 0, sizeof(struct tle_evq_param));
+
+ evq_params.socket_id = socket_id;
+ evq_params.max_events = max_events;
+ evq = tle_evq_create(&evq_params);
+ return evq;
+}
+
+struct tle_stream *
+test_tle_udp_gen_base::setup_stream(struct tle_ctx *ctx, int family,
+ const char *l_ip, const char *r_ip, int l_port, int r_port)
+{
+ struct tle_stream *stream;
+ struct tle_udp_stream_param stream_prm;
+ struct sockaddr_in *ip4_addr;
+ struct sockaddr_in6 *ip6_addr;
+ int32_t ret;
+
+ memset(&stream_prm, 0, sizeof(stream_prm));
+
+ if (family == AF_INET) {
+ ip4_addr = (struct sockaddr_in *) &stream_prm.local_addr;
+ ip4_addr->sin_family = AF_INET;
+ ip4_addr->sin_port = htons(l_port);
+ ip4_addr->sin_addr.s_addr = inet_addr(l_ip);
+
+ ip4_addr = (struct sockaddr_in *) &stream_prm.remote_addr;
+ ip4_addr->sin_family = AF_INET;
+ ip4_addr->sin_port = htons(r_port);
+ ip4_addr->sin_addr.s_addr = inet_addr(r_ip);
+ } else if (family == AF_INET6) {
+ ip6_addr = (struct sockaddr_in6 *) &stream_prm.local_addr;
+ ip6_addr->sin6_family = AF_INET6;
+ inet_pton(AF_INET6, l_ip, &ip6_addr->sin6_addr);
+ ip6_addr->sin6_port = htons(l_port);
+
+ ip6_addr = (struct sockaddr_in6 *) &stream_prm.remote_addr;
+ ip6_addr->sin6_family = AF_INET6;
+ inet_pton(AF_INET6, r_ip, &ip6_addr->sin6_addr);
+ ip6_addr->sin6_port = htons(r_port);
+ } else {
+ printf("Invalid address family, stream not created\n");
+ return NULL;
+ }
+
+ /* Not supporting callbacks and events at the moment */
+ /* TODO: Add tests which use cb's and events. */
+ stream_prm.recv_ev = tle_event_alloc(evq, nullptr);
+ stream_prm.send_ev = tle_event_alloc(evq, nullptr);
+
+ stream = tle_udp_stream_open(ctx,
+ (const struct tle_udp_stream_param *) &stream_prm);
+
+ return stream;
+}
+
+int
+test_tle_udp_gen_base::close_streams(vector<struct stream_s> streams)
+{
+ int rc;
+
+ for (auto &s : streams) {
+ rc = tle_udp_stream_close(s.ptr);
+ if (rc != 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+test_tle_udp_gen_base::del_devs(vector<struct dev_s> devs)
+{
+ int rc;
+
+ for (auto &d : devs) {
+ rc = tle_del_dev(d.ptr);
+ if (rc != 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+class tle_rx_test : public test_tle_udp_gen_base {
+public:
+ virtual void SetUp(void)
+ {
+ /* Generate RX pcap file, for RX tests, then
+ * follow setup steps as in base class */
+ tp = GetParam();
+
+ for(auto &s : tp.gen_streams) {
+ prepare_pcaps(s.src_ip.c_str(), s.dst_ip.c_str(),
+ s.src_port, s.dst_port, s.nb_pkts,
+ s.bad_chksum_l3, s.bad_chksum_l4, RX_PCAP);
+ }
+ test_tle_udp_gen_base::SetUp();
+ }
+};
+
+class tle_rx_enobufs: public tle_rx_test { };
+
+class tle_tx_test: public test_tle_udp_gen_base {
+public:
+ virtual void SetUp(void)
+ {
+ /* Generate 1-packet PCAP RX file so that virtual device can be
+ * initialized (needs a pcap file present during init), then
+ * follow setup steps as in base class
+ */
+ prepare_pcaps("10.0.0.1", "10.0.0.1", 100, 100, 1, 0, 0,
+ RX_PCAP);
+ test_tle_udp_gen_base::SetUp();
+ }
+};
+
+#endif /* TEST_TLE_UDP_STREAM_GEN_H_ */
diff --git a/test/timer/Makefile b/test/timer/Makefile
new file mode 100644
index 0000000..159faeb
--- /dev/null
+++ b/test/timer/Makefile
@@ -0,0 +1,42 @@
+# Copyright (c) 2016 Intel Corporation.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+ifeq ($(RTE_TARGET),)
+$(error "Please define RTE_TARGET environment variable")
+endif
+
+ifeq ($(TLDK_ROOT),)
+$(error "Please define TLDK_ROOT environment variable")
+endif
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = test_timer
+
+# all source are stored in SRCS-y
+SRCS-y += test_timer.c
+
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -I$(RTE_OUTPUT)/include
+
+LDLIBS += -L$(RTE_OUTPUT)/lib
+LDLIBS += -ltle_timer
+
+EXTRA_CFLAGS += -O3
+
+include $(TLDK_ROOT)/mk/tle.app.mk
diff --git a/test/timer/test_timer.c b/test/timer/test_timer.c
new file mode 100644
index 0000000..cde4b62
--- /dev/null
+++ b/test/timer/test_timer.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2016 Intel Corporation.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_eal.h>
+#include <rte_errno.h>
+#include <rte_random.h>
+#include <rte_log.h>
+
+#include <tle_timer.h>
+
+#define MAX_TIMER_BURST 0x20
+
+#define RDTSC_TO_SEC(t, h) ((double)(t)/(h))
+
+struct test_elements {
+ uint32_t expected_tick;
+ uint32_t active;
+ void *stop_handle;
+ uint32_t id;
+};
+
+struct timer_test_main {
+ struct tle_timer_wheel *tmr;
+ uint64_t last_run_time;
+ uint32_t current_tick;
+ uint32_t seed;
+ uint32_t ntimers;
+ uint32_t niter;
+ uint32_t ticks_per_iter;
+ struct tle_timer_wheel_args prm;
+ struct test_elements *test_elts;
+};
+
+struct timer_test_main *global_test_main;
+
+/** \brief 32-bit random number generator */
+static inline uint32_t
+random_uint32_t(uint32_t *seed)
+{
+ *seed = (1664525 * *seed) + 1013904223;
+ return *seed;
+}
+
+static void
+run_wheel(struct timer_test_main *tm, uint64_t interval, uint32_t *expired)
+{
+ uint32_t i, j, k;
+ uint64_t now = tm->last_run_time + tm->prm.tick_size;
+ uint32_t nb_tick;
+ struct test_elements *te[MAX_TIMER_BURST];
+
+ nb_tick = interval / tm->prm.tick_size;
+
+ for (i = 0; i < nb_tick; i++)
+ {
+ tle_timer_expire(tm->tmr, now);
+ tm->last_run_time = now;
+
+ k = tle_timer_get_expired_bulk(tm->tmr, (void **)te,
+ RTE_DIM(te));
+ while (k != 0) {
+ for (j = 0; j != k; j++)
+ {
+ if (tm->current_tick != te[j]->expected_tick)
+ RTE_LOG(ERR, USER1,
+ "%s: [%u] expired at tick=%u, "
+ "(not tick=%u)\n",
+ __func__, te[j]->id,
+ tm->current_tick,
+ te[j]->expected_tick);
+
+ te[j]->active = 0;
+ te[j]->stop_handle = NULL;
+ *expired += 1;
+ }
+
+ k = tle_timer_get_expired_bulk(tm->tmr, (void **)te,
+ RTE_DIM(te));
+ };
+ now += (tm->prm.tick_size);
+ tm->current_tick++;
+ }
+}
+
+static int
+test_timer_rdtsc(void)
+{
+ struct timer_test_main tm;
+ struct test_elements *te;
+ uint64_t expiration_time;
+ uint32_t i, j, k;
+ uint64_t initial_wheel_offset;
+ struct tle_timer_wheel_args prm;
+ uint64_t start_tsc, cur_tsc, diff_tsc;
+ uint64_t max_expiration_time = 0;
+ uint32_t adds = 0, deletes = 0, expires = 0;
+ double ops_per_sec;
+ uint64_t hz;
+
+ memset(&tm, 0, sizeof(tm));
+ /* Default values */
+ tm.ntimers = 1000000;
+ tm.seed = 0xDEADDABE;
+ tm.niter = 1000;
+ tm.ticks_per_iter = 57;
+ tm.current_tick = 0;
+ tm.test_elts = rte_zmalloc_socket(NULL,
+ tm.ntimers * sizeof(tm.test_elts[0]), RTE_CACHE_LINE_SIZE,
+ SOCKET_ID_ANY);
+ global_test_main = &tm;
+
+ hz = rte_get_tsc_hz(); /* timer in cpu cycles */
+ prm.tick_size = hz / 10;
+ prm.max_timer = tm.ntimers;
+ prm.socket_id = SOCKET_ID_ANY;
+
+ start_tsc = rte_rdtsc();
+
+ tm.prm = prm;
+ tm.tmr = tle_timer_create(&prm, start_tsc);
+ tm.last_run_time = start_tsc;
+
+ if (tm.tmr == NULL){
+ printf("%s: tcp_timer_wheel_init failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ printf("hz=%lu, tick_size=%u, ntimers=%u, niter=%u, "
+ "ticks_per_iter=%u\n", hz, prm.tick_size, tm.ntimers,
+ tm.niter, tm.ticks_per_iter);
+
+ /* Prime offset */
+ initial_wheel_offset = tm.ticks_per_iter;
+
+ run_wheel(&tm, initial_wheel_offset * prm.tick_size, &expires);
+
+ /* Prime the pump */
+ for (i = 0; i < tm.ntimers; i++)
+ {
+ te= &tm.test_elts[i];
+ te->id = i;
+
+ do {
+ expiration_time =
+ (random_uint32_t(&tm.seed) & ((1<<17) - 1));
+ } while (expiration_time == 0);
+
+ if (expiration_time > max_expiration_time)
+ max_expiration_time = expiration_time;
+
+ te->expected_tick = expiration_time + initial_wheel_offset;
+ te->stop_handle = tle_timer_start(tm.tmr, te,
+ expiration_time * prm.tick_size);
+ if (te->stop_handle == NULL) {
+ RTE_LOG(ERR, USER1, "%s: timer start error=%d\n",
+ __func__, rte_errno);
+ break;
+ }
+ te->active = 1;
+ }
+
+ adds += i;
+
+ for (i = 0; i < tm.niter; i++)
+ {
+ run_wheel(&tm, initial_wheel_offset * prm.tick_size, &expires);
+
+ for (k = 0, j = 0; j < tm.ntimers; j++) {
+ te = &tm.test_elts[j];
+
+ if (te->active) {
+ tle_timer_stop(tm.tmr, te->stop_handle);
+ te->active = 0;
+ te->stop_handle = NULL;
+ k++;
+
+ if (k > tm.ntimers/4)
+ break;
+ }
+ }
+
+ deletes += k;
+
+ for (k = 0, j = 0; j < tm.ntimers; j++)
+ {
+ te = &tm.test_elts[j];
+
+ if (!te->active) {
+ do {
+ expiration_time =
+ (random_uint32_t(&tm.seed) &
+ ((1<<17) - 1));
+ } while (expiration_time == 0);
+
+ if (expiration_time > max_expiration_time)
+ max_expiration_time = expiration_time;
+
+ te->expected_tick = expiration_time +
+ tm.current_tick;
+ te->stop_handle = tle_timer_start(tm.tmr, te,
+ expiration_time * prm.tick_size);
+ if (te->stop_handle == NULL) {
+ RTE_LOG(ERR, USER1,
+ "%s: timer start error =%d\n",
+ __func__, rte_errno);
+ break;
+ }
+ te->active = 1;
+ k++;
+
+ if (k > tm.ntimers/4)
+ break;
+ }
+ }
+
+ adds += k;
+ }
+
+ run_wheel(&tm, (max_expiration_time + 1) * prm.tick_size, &expires);
+
+ cur_tsc = rte_rdtsc();
+ diff_tsc = cur_tsc - start_tsc;
+
+ ops_per_sec = ((double)adds + deletes +
+ tm.current_tick) / RDTSC_TO_SEC(diff_tsc, hz);
+
+ printf("%u adds, %u deletes, %u expires, %u ticks\n"
+ "test ran %.2f seconds, %.2f ops/second, %.2f cycles/op\n",
+ adds, deletes, expires, tm.current_tick,
+ RDTSC_TO_SEC(diff_tsc, hz), ops_per_sec,
+ (double)hz/ops_per_sec);
+
+ rte_free(tm.test_elts);
+ tle_timer_free(tm.tmr);
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int32_t rc;
+
+ rc = rte_eal_init(argc, argv);
+ if (rc < 0)
+ rte_exit(EXIT_FAILURE,
+ "%s: rte_eal_init failed with error code: %d\n",
+ __func__, rc);
+
+ rc = test_timer_rdtsc();
+ if (rc != 0)
+ printf("test_timer_rdtsc TEST FAILED\n");
+ else
+ printf("test_timer_rdtsc TEST OK\n");
+
+ return rc;
+}