diff options
author | 2017-02-21 18:12:20 +0000 | |
---|---|---|
committer | 2017-02-24 16:37:08 +0000 | |
commit | aa97dd1ce910b839fed46ad55d1e70e403f5a930 (patch) | |
tree | f6f0fd494eaf499859bff9f20f5ddfac9ab99233 /test/gtest | |
parent | f5f10013ffef8e4ac1071087b8492fe6380d98fe (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/gtest')
-rw-r--r-- | test/gtest/Makefile | 12 | ||||
-rw-r--r-- | test/gtest/README | 82 | ||||
-rw-r--r-- | test/gtest/main.cpp | 33 | ||||
-rw-r--r-- | test/gtest/test_common.cpp | 276 | ||||
-rw-r--r-- | test/gtest/test_common.h | 97 | ||||
-rw-r--r-- | test/gtest/test_scapy_gen.py | 96 | ||||
-rw-r--r-- | test/gtest/test_tle_ctx.cpp | 130 | ||||
-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.cpp | 195 | ||||
-rw-r--r-- | test/gtest/test_tle_tcp_stream.h | 251 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_ctx.cpp | 42 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_destroy.cpp | 4 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_destroy.h | 8 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_dev.cpp | 27 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_dev.h | 23 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_event.h | 2 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_stream.cpp | 78 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_stream.h | 200 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_stream_gen.cpp | 444 | ||||
-rw-r--r-- | test/gtest/test_tle_udp_stream_gen.h | 541 |
20 files changed, 2355 insertions, 194 deletions
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_ */ |