aboutsummaryrefslogtreecommitdiffstats
path: root/test/gtest/test_tle_udp_stream_gen.h
diff options
context:
space:
mode:
Diffstat (limited to 'test/gtest/test_tle_udp_stream_gen.h')
-rw-r--r--test/gtest/test_tle_udp_stream_gen.h541
1 files changed, 541 insertions, 0 deletions
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_ */