From aa97dd1ce910b839fed46ad55d1e70e403f5a930 Mon Sep 17 00:00:00 2001 From: Konstantin Ananyev Date: Tue, 21 Feb 2017 18:12:20 +0000 Subject: 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 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 Signed-off-by: Karol Latecki Signed-off-by: Daniel Mrzyglod Signed-off-by: Konstantin Ananyev --- test/Makefile | 1 + test/gtest/Makefile | 12 +- test/gtest/README | 82 ++--- test/gtest/main.cpp | 33 +- test/gtest/test_common.cpp | 276 +++++++++++++++++ test/gtest/test_common.h | 97 ++++++ test/gtest/test_scapy_gen.py | 96 ++++++ test/gtest/test_tle_ctx.cpp | 130 ++++++++ test/gtest/test_tle_ctx.h | 23 ++ test/gtest/test_tle_tcp_stream.cpp | 195 ++++++++++++ test/gtest/test_tle_tcp_stream.h | 251 +++++++++++++++ test/gtest/test_tle_udp_ctx.cpp | 42 --- test/gtest/test_tle_udp_ctx.h | 23 -- test/gtest/test_tle_udp_destroy.cpp | 4 +- test/gtest/test_tle_udp_destroy.h | 8 +- test/gtest/test_tle_udp_dev.cpp | 27 +- test/gtest/test_tle_udp_dev.h | 23 +- test/gtest/test_tle_udp_event.h | 2 +- test/gtest/test_tle_udp_stream.cpp | 78 ++++- test/gtest/test_tle_udp_stream.h | 200 ++++++++---- test/gtest/test_tle_udp_stream_gen.cpp | 444 +++++++++++++++++++++++++++ test/gtest/test_tle_udp_stream_gen.h | 541 +++++++++++++++++++++++++++++++++ test/timer/Makefile | 42 +++ test/timer/test_timer.c | 272 +++++++++++++++++ 24 files changed, 2689 insertions(+), 213 deletions(-) create mode 100644 test/gtest/test_common.cpp create mode 100644 test/gtest/test_common.h create mode 100644 test/gtest/test_scapy_gen.py create mode 100644 test/gtest/test_tle_ctx.cpp create mode 100644 test/gtest/test_tle_ctx.h create mode 100644 test/gtest/test_tle_tcp_stream.cpp create mode 100644 test/gtest/test_tle_tcp_stream.h delete mode 100644 test/gtest/test_tle_udp_ctx.cpp delete mode 100644 test/gtest/test_tle_udp_ctx.h create mode 100644 test/gtest/test_tle_udp_stream_gen.cpp create mode 100644 test/gtest/test_tle_udp_stream_gen.h create mode 100644 test/timer/Makefile create mode 100644 test/timer/test_timer.c (limited to 'test') 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 #include #include -#include + #include #include +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_ctx.h b/test/gtest/test_tle_ctx.h new file mode 100644 index 0000000..5c6f2c3 --- /dev/null +++ b/test/gtest/test_tle_ctx.h @@ -0,0 +1,23 @@ +/* + * 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_CTX_H_ +#define TEST_TLE_CTX_H_ + +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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_ctx.h b/test/gtest/test_tle_udp_ctx.h deleted file mode 100644 index af02440..0000000 --- a/test/gtest/test_tle_udp_ctx.h +++ /dev/null @@ -1,23 +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. - */ - -#ifndef TEST_TLE_UDP_CTX_H_ -#define TEST_TLE_UDP_CTX_H_ - -#include -#include -#include - -#endif /* TEST_TLE_UDP_CTX_H_ */ 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 #include -#include +#include 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 #include - -#include +#include #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 devs; + struct tle_ctx *ctx; + struct tle_dev *dev; + struct tle_ctx_param prm; + struct tle_dev_param dev_prm; + vector 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 #include -#include +#include #include 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 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 +#include +#include #include +#include +#include #include #include #include -#include +#include #include -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 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 devs; + vector 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(&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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 *>(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 *>(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 devs; + vector streams; + vector gen_streams; +}; + +const char *vdevargs[] = {VDEV_NAME",rx_pcap=" RX_PCAP",tx_pcap=" TX_PCAP}; + +class test_tle_udp_gen_base : public testing::TestWithParam { +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 streams); + int del_devs(vector 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(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(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 routes4; + map 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 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 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 +#include +#include +#include +#include +#include +#include + +#include + +#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; +} -- cgit 1.2.3-korg