diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index aa181a4abe..aefa3594d4 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -519,6 +519,8 @@ def getstatusoutput(cmd): 'bp_sim_stf.cpp', 'trex_build_info.cpp', 'dpdk_drv_filter.cpp', + 'tunnel.cpp', + 'gtpu.cpp', 'drivers/trex_driver_base.cpp', 'drivers/trex_driver_bnxt.cpp', diff --git a/scripts/create_pdps.sh b/scripts/create_pdps.sh new file mode 100755 index 0000000000..452fa11898 --- /dev/null +++ b/scripts/create_pdps.sh @@ -0,0 +1,39 @@ +#! /bin/bash + +# GRPC address of EDA +EDA_GRPC_ADDRESS=":9111" +PDP_TUNNEL_REM_IP="" +PDP_TUNNEL_LOC_IP="" + +DATA_FILE="/etc/gtpu-tunnels.csv" + +# Creates a PDP context and set the PDP_CTX_ID variable as a result. +create_pdp_ctx() { + local ENDPOINT_IP=$1 + local LOCAL_TEID=$2 + local REMOTE_TEID=$3 + + /opt/eda-tools/bin/eda-grpc-cli CreatePDP --server.address $EDA_GRPC_ADDRESS \ + "{\"pdp_ctx_attributes\": {\"endpoint\":{\"ip_address\":\"$ENDPOINT_IP\", \ + \"ip_address_version\":\"IPV4\"}, \"tunnel\":{\"local_ip\":\"$PDP_TUNNEL_REM_IP\", \ + \"remote_ip\":\"$PDP_TUNNEL_LOC_IP\", \"local_teid\":$REMOTE_TEID, \"remote_teid\":$LOCAL_TEID}}}" +} + +echo "# endpoint-ip,src-teid,dst-teid" > $DATA_FILE + +i0=16 +teid=0 +for i1 in {0..0} +do + for i2 in {0..0} + do + for i3 in {0..255} + do + IP="$i0.$i1.$i2.$i3" + create_pdp_ctx $IP $teid $teid + echo "$IP,$teid,$teid" >> $DATA_FILE + + teid=$(( $teid + 1 )) + done + done +done diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py index 625ea8aa22..4b417b75ae 100755 --- a/scripts/dpdk_setup_ports.py +++ b/scripts/dpdk_setup_ports.py @@ -602,8 +602,10 @@ def try_bind_to_vfio_pci(self, to_bind_list): with open(krnl_params_file) as f: krnl_params = f.read() # IOMMU is always enabled on Power systems - if march != 'ppc64le' and 'iommu=' not in krnl_params: - raise VFIOBindErr('vfio-pci is not an option here') + # AWS EC2 instances do not have IOMMU enabled. + # Try to load vfio_pci in any case. + # if march != 'ppc64le' and 'iommu=' not in krnl_params: + # raise VFIOBindErr('vfio-pci is not an option here') if 'vfio_pci' not in dpdk_nic_bind.get_loaded_modules(): ret = os.system('modprobe vfio_pci') if ret: diff --git a/src/gtpu.cpp b/src/gtpu.cpp new file mode 100644 index 0000000000..7cbee26647 --- /dev/null +++ b/src/gtpu.cpp @@ -0,0 +1,221 @@ +#include +#include +#include + +#include +#include +#include + +#include "common/c_common.h" +#include "utl_yaml.h" +#include "inet_pton.h" + +#include "gtpu.h" + +int GTPU::Encap(struct rte_mbuf *pkt) +{ + if (rte_pktmbuf_headroom(pkt) < sizeof(gtpu_header_t)) { + return -1; + } + + rte_ether_hdr * eth = rte_pktmbuf_mtod(pkt, rte_ether_hdr *); + if (eth->ether_type != htons(RTE_ETHER_TYPE_IPV4)) { + return 0; + } + rte_ipv4_hdr * ip = (rte_ipv4_hdr *)(eth + 1); + + // check whether the source is a known endpoint ip address + auto it = m_teids_by_endpoint.find(ip->src_addr); + if (it == m_teids_by_endpoint.end()) { + return 0; + } + uint32_t dteid = it->second.dteid; + + // make space for the ip+udp+gtpu headers + rte_ether_hdr * new_eth = (rte_ether_hdr *) rte_pktmbuf_prepend(pkt, sizeof(ip4_gtpu_header_t)); + + // copy over the ethernet header + new_eth->ether_type = htons(RTE_ETHER_TYPE_IPV4); + rte_ether_addr_copy(ð->s_addr, &new_eth->s_addr); + rte_ether_addr_copy(ð->d_addr, &new_eth->d_addr); + + // Set the outer headers + const uint32_t mask = (2<<16) -1; + uint32_t random_src_port = it->second.steid & mask; + m_rewrite.udp.src_port = htons(random_src_port); + ip4_gtpu_header_t * ip4_gtpu = (ip4_gtpu_header_t *)(new_eth + 1); + memcpy(ip4_gtpu, &m_rewrite, sizeof(ip4_gtpu_header_t)); + + // ipv4 + ip4_gtpu->ip4.total_length = htons(pkt->pkt_len - RTE_ETHER_HDR_LEN); + + // udp + ip4_gtpu->udp.dgram_len = htons(pkt->pkt_len - RTE_ETHER_HDR_LEN - sizeof(rte_ipv4_hdr)); + + // gtpu + ip4_gtpu->gtpu.teid = dteid; + ip4_gtpu->gtpu.length = htons(pkt->pkt_len - RTE_ETHER_HDR_LEN - sizeof(ip4_gtpu_header_t)); + + // Offload the checksum calculation of the inner header only. + // The ENA driver does not support both inner and outer header checksum offload. It is + // easier and faster to calculate the outer ip checksum and let the HW do the rest. + // The offload flags can be left untouched, they were originally set for the inner + // headers anyway. + pkt->l2_len += sizeof(ip4_gtpu_header_t); // Indicate where the inner ip hdr starts. + ip = &ip4_gtpu->ip4; + ip->hdr_checksum = rte_ipv4_cksum(ip); + + return 0; +} + +int GTPU::Decap(struct rte_mbuf *pkt) +{ + if (rte_pktmbuf_data_len(pkt) < sizeof(ip4_gtpu_header_t)) { + return 0; + } + + rte_ether_hdr * eth = rte_pktmbuf_mtod(pkt, rte_ether_hdr *); + if (eth->ether_type != htons(RTE_ETHER_TYPE_IPV4)) { + return 0; + } + + // ip+udp check + ip4_gtpu_header_t * ip4_gtpu = (ip4_gtpu_header_t *)(eth + 1); + if (ip4_gtpu->ip4.next_proto_id != IPPROTO_UDP + || ip4_gtpu->udp.dst_port != htons(GTPU_UDP_PORT) + ) + return 0; + + // gtpu validation + if ((ip4_gtpu->gtpu.ver_flags & GTPU_VER_MASK) != GTPU_V1_VER + || (ip4_gtpu->gtpu.ver_flags & GTPU_PT_BIT) == 0 + || ip4_gtpu->gtpu.type != GTPU_TYPE_GPDU + ) + return 0; + + // check whether the destination is a known endpoint ip address + rte_ipv4_hdr * ip = (rte_ipv4_hdr *)(ip4_gtpu + 1); + auto it = m_teids_by_endpoint.find(ip->dst_addr); + if (it == m_teids_by_endpoint.end()) { + return -1; + } + uint32_t steid = it->second.steid; + // Verify the teid + if (steid != ip4_gtpu->gtpu.teid) { + return -1; + } + + // Srip off the ip+udp+gtpu headers + rte_ether_hdr * new_eth = (rte_ether_hdr *) rte_pktmbuf_adj(pkt, sizeof(ip4_gtpu_header_t)); + + // copy over the ethernet header + new_eth->ether_type = htons(RTE_ETHER_TYPE_IPV4); + rte_ether_addr_copy(ð->s_addr, &new_eth->s_addr); + rte_ether_addr_copy(ð->d_addr, &new_eth->d_addr); + + return 0; +} + +void GTPU::Parse(YAML::Node const& node) +{ + if (!utl_yaml_read_ip_addr(node, "src_address", m_src_addr)) { + ASSERT_MSG(false, "Can't find 'src_address' for gtpu tunnel"); + } + if (!utl_yaml_read_ip_addr(node, "dst_address", m_dst_addr)) { + ASSERT_MSG(false, "Can't find 'dst_address' for gtpu tunnel"); + } + if (node.FindValue("data_file")) { + std::string filename; + node["data_file"] >> filename; + if (LoadDataFile(filename) < 0) + ASSERT_MSG(false, "Failed to load data_file for gtpu tunnel"); + } else { + ASSERT_MSG(false, "Missing data_file name for gtpu_tunnel"); + } +} + +void GTPU::Prepare() +{ + memset(&m_rewrite, 0, sizeof(ip4_gtpu_header_t)); + + m_rewrite.ip4.version_ihl = 0x45; + m_rewrite.ip4.time_to_live = 64; + m_rewrite.ip4.next_proto_id = IPPROTO_UDP; + m_rewrite.ip4.src_addr = htonl(m_src_addr); + m_rewrite.ip4.dst_addr = htonl(m_dst_addr); + + // Source port will later be randomized during encapsulation + m_rewrite.udp.src_port = htons(GTPU_UDP_PORT); + m_rewrite.udp.dst_port = htons(GTPU_UDP_PORT); + + m_rewrite.gtpu.ver_flags = GTPU_V1_VER | GTPU_PT_BIT; + m_rewrite.gtpu.type = GTPU_TYPE_GPDU; +} + +std::string GTPU::GetCSVToken(std::string& s, size_t & pos) +{ + std::string token; + size_t start = pos; + + if (pos == std::string::npos) + return token; + + pos = s.find(',', pos); + if (pos == std::string::npos) { + // not found + token = s.substr(start); + } else { + token = s.substr(start, pos-start); + pos++; + } + return token; +} + +int GTPU::LoadDataFile(std::string &filename) +{ + std::ifstream file(filename); + if (!file.is_open()) { + return -1; + } + + std::string line; + std::string endpoint_addr, src_teid, dst_teid; + size_t pos; + while (std::getline(file, line)) + { + // skip comments + if (line.front() == '#') + continue; + + pos = 0; + endpoint_addr = GetCSVToken(line, pos); + src_teid = GetCSVToken(line, pos); + dst_teid = GetCSVToken(line, pos); + + if (endpoint_addr.empty() || src_teid.empty() || dst_teid.empty()) { + printf("Missing token in line: %s\n", line.c_str()); + return -1; + } + if (AddTunnel(endpoint_addr, src_teid, dst_teid)) + return -1; + } + + file.close(); + return 0; +} + +int GTPU::AddTunnel(std::string& endpoint_addr, std::string& src_teid, std::string& dst_teid) +{ + uint32_t ip, steid, dteid; + if (my_inet_pton4((char *)endpoint_addr.c_str(), (unsigned char *)&ip) == 0) { + printf("Invalid endpoint IP address: %s\n", endpoint_addr.c_str()); + return -1; + } + steid = (uint32_t)std::stoll(src_teid); + dteid = (uint32_t)std::stoll(dst_teid); + // ip is already in network byte order + m_teids_by_endpoint[ip] = Teids{.steid=htonl(steid), .dteid=htonl(dteid)}; + (void)steid; + + return 0; +} diff --git a/src/gtpu.h b/src/gtpu.h new file mode 100644 index 0000000000..033c318256 --- /dev/null +++ b/src/gtpu.h @@ -0,0 +1,70 @@ +#ifndef _GTPU_H_ +#define _GTPU_H_ + +#include +#include +#include + +#include "tunnel.h" + +typedef struct +{ + uint8_t ver_flags; + uint8_t type; + uint16_t length; /* length in octets of the data following the fixed part of the header */ + uint32_t teid; +} gtpu_header_t; + +#define GTPU_V1_HDR_LEN 8 + +#define GTPU_VER_MASK (7<<5) +#define GTPU_PT_BIT (1<<4) +#define GTPU_E_BIT (1<<2) +#define GTPU_S_BIT (1<<1) +#define GTPU_PN_BIT (1<<0) +#define GTPU_E_S_PN_BIT (7<<0) + +#define GTPU_V1_VER (1<<5) + +#define GTPU_TYPE_GPDU 255 + +#define GTPU_UDP_PORT 2152 + +typedef struct __attribute__((packed)) +{ + rte_ipv4_hdr ip4; /* 20 bytes */ + rte_udp_hdr udp; /* 8 bytes */ + gtpu_header_t gtpu; /* 8 bytes */ +} ip4_gtpu_header_t; + +class GTPU: public Tunnel { +public: + GTPU(YAML::Node const& node) { + Parse(node); + Prepare(); + } + ~GTPU() {} + + int Encap(struct rte_mbuf *pkt) override; + int Decap(struct rte_mbuf *pkt) override; +private: + // TEID pairs in network byte order + typedef struct { + uint32_t steid, dteid; + } Teids; + + // Tunnel src-dst ipv4 addresses + uint32_t m_src_addr, m_dst_addr; + // Prepared rewrite string for encapsulation + ip4_gtpu_header_t m_rewrite; + // Teids indexed by the endpoint address in network byte order + std::map m_teids_by_endpoint; + + void Parse(YAML::Node const&); + void Prepare(); + std::string GetCSVToken(std::string& s, size_t & pos); + int LoadDataFile(std::string &filename); + int AddTunnel(std::string& endpoint_addr, std::string& src_teid, std::string& dst_teid); +}; + +#endif diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index e62b30b5c5..7246ca027c 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -105,6 +105,7 @@ extern "C" { #include "astf/astf_db.h" #include "utl_offloads.h" #include "trex_defs.h" +#include "tunnel.h" #define MAX_PKT_BURST 32 #define BP_MAX_CORES 48 @@ -1291,6 +1292,7 @@ COLD_FUNC void CPhyEthIF::rx_queue_setup(uint16_t rx_queue_id, "rte_eth_rx_queue_setup: " "err=%d, port=%u\n", ret, m_repid); + Tunnel::InstallRxCallback(m_repid, rx_queue_id); } COLD_FUNC void CPhyEthIF::tx_queue_setup(uint16_t tx_queue_id, @@ -1307,7 +1309,7 @@ COLD_FUNC void CPhyEthIF::tx_queue_setup(uint16_t tx_queue_id, rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: " "err=%d, port=%u queue=%u\n", ret, m_repid, tx_queue_id); - + Tunnel::InstallTxCallback(m_repid, tx_queue_id); } COLD_FUNC void CPhyEthIF::stop(){ @@ -5915,6 +5917,7 @@ COLD_FUNC int update_global_info_from_platform_file(){ cg->m_mac_info[i].copy_src(( char *)g_opts->m_mac_addr[i].u.m_mac.src) ; cg->m_mac_info[i].copy_dest(( char *)g_opts->m_mac_addr[i].u.m_mac.dest) ; g_opts->m_mac_addr[i].u.m_mac.is_set = 1; + g_opts->m_mac_addr[i].m_tunnel = cg->m_mac_info[i].m_tunnel; g_opts->m_ip_cfg[i].set_def_gw(cg->m_mac_info[i].get_def_gw()); g_opts->m_ip_cfg[i].set_ip(cg->m_mac_info[i].get_ip()); diff --git a/src/pal/linux_dpdk/dpdk1711_x86_64/rte_config.h b/src/pal/linux_dpdk/dpdk1711_x86_64/rte_config.h index f13ccebc18..56c728954f 100644 --- a/src/pal/linux_dpdk/dpdk1711_x86_64/rte_config.h +++ b/src/pal/linux_dpdk/dpdk1711_x86_64/rte_config.h @@ -69,8 +69,8 @@ #undef RTE_LIBRTE_IEEE1588 #undef RTE_ETHDEV_QUEUE_STAT_CNTRS #define RTE_ETHDEV_QUEUE_STAT_CNTRS 16 -#undef RTE_ETHDEV_RXTX_CALLBACKS -// TREX_PATCH RTE_ETHDEV_RXTX_CALLBACKS used to be 1 +//#undef RTE_ETHDEV_RXTX_CALLBACKS +#define RTE_ETHDEV_RXTX_CALLBACKS 1 #undef RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS #undef RTE_ETHDEV_TX_PREPARE_NOOP #undef RTE_LIBRTE_PCI_BUS diff --git a/src/pal/linux_dpdk/dpdk1805_x86_64/rte_config.h b/src/pal/linux_dpdk/dpdk1805_x86_64/rte_config.h index 0d2adfbd49..c00d435f2d 100755 --- a/src/pal/linux_dpdk/dpdk1805_x86_64/rte_config.h +++ b/src/pal/linux_dpdk/dpdk1805_x86_64/rte_config.h @@ -82,8 +82,8 @@ #undef RTE_LIBRTE_IEEE1588 #undef RTE_ETHDEV_QUEUE_STAT_CNTRS #define RTE_ETHDEV_QUEUE_STAT_CNTRS 16 -#undef RTE_ETHDEV_RXTX_CALLBACKS -//#define RTE_ETHDEV_RXTX_CALLBACKS 1 +//#undef RTE_ETHDEV_RXTX_CALLBACKS +#define RTE_ETHDEV_RXTX_CALLBACKS 1 #undef RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS #undef RTE_ETHDEV_TX_PREPARE_NOOP #undef RTE_LIBRTE_IFPGA_BUS diff --git a/src/pal/linux_dpdk/dpdk1808_x86_64/rte_config.h b/src/pal/linux_dpdk/dpdk1808_x86_64/rte_config.h index 0afbc411c1..22957ca7c1 100644 --- a/src/pal/linux_dpdk/dpdk1808_x86_64/rte_config.h +++ b/src/pal/linux_dpdk/dpdk1808_x86_64/rte_config.h @@ -82,8 +82,8 @@ #undef RTE_LIBRTE_IEEE1588 #undef RTE_ETHDEV_QUEUE_STAT_CNTRS #define RTE_ETHDEV_QUEUE_STAT_CNTRS 16 -#undef RTE_ETHDEV_RXTX_CALLBACKS -//#define RTE_ETHDEV_RXTX_CALLBACKS 1 +//#undef RTE_ETHDEV_RXTX_CALLBACKS +#define RTE_ETHDEV_RXTX_CALLBACKS 1 #undef RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS #undef RTE_ETHDEV_TX_PREPARE_NOOP #undef RTE_LIBRTE_IFPGA_BUS diff --git a/src/pal/linux_dpdk/dpdk1905_x86_64/rte_config.h b/src/pal/linux_dpdk/dpdk1905_x86_64/rte_config.h index 63d8bf4c34..93ecfb5183 100644 --- a/src/pal/linux_dpdk/dpdk1905_x86_64/rte_config.h +++ b/src/pal/linux_dpdk/dpdk1905_x86_64/rte_config.h @@ -97,8 +97,8 @@ #undef RTE_LIBRTE_IEEE1588 #undef RTE_ETHDEV_QUEUE_STAT_CNTRS #define RTE_ETHDEV_QUEUE_STAT_CNTRS 16 -#undef RTE_ETHDEV_RXTX_CALLBACKS -//#define RTE_ETHDEV_RXTX_CALLBACKS 1 +//#undef RTE_ETHDEV_RXTX_CALLBACKS +#define RTE_ETHDEV_RXTX_CALLBACKS 1 #undef RTE_ETHDEV_PROFILE_WITH_VTUNE #undef RTE_ETHDEV_TX_PREPARE_NOOP #undef RTE_LIBRTE_COMMON_DPAAX diff --git a/src/pal/linux_dpdk/dpdk2002_x86_64/rte_config.h b/src/pal/linux_dpdk/dpdk2002_x86_64/rte_config.h index 2fe05e9aee..4c833f9620 100644 --- a/src/pal/linux_dpdk/dpdk2002_x86_64/rte_config.h +++ b/src/pal/linux_dpdk/dpdk2002_x86_64/rte_config.h @@ -97,8 +97,8 @@ #undef RTE_LIBRTE_IEEE1588 #undef RTE_ETHDEV_QUEUE_STAT_CNTRS #define RTE_ETHDEV_QUEUE_STAT_CNTRS 16 -#undef RTE_ETHDEV_RXTX_CALLBACKS -//#define RTE_ETHDEV_RXTX_CALLBACKS 1 +//#undef RTE_ETHDEV_RXTX_CALLBACKS +#define RTE_ETHDEV_RXTX_CALLBACKS 1 #undef RTE_ETHDEV_PROFILE_WITH_VTUNE #undef RTE_ETHDEV_TX_PREPARE_NOOP #undef RTE_LIBRTE_COMMON_DPAAX diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp index 7a855bf095..cebebafddb 100755 --- a/src/platform_cfg.cpp +++ b/src/platform_cfg.cpp @@ -26,6 +26,7 @@ limitations under the License. #include "utl_yaml.h" #include "platform_cfg.h" #include "trex_global.h" +#include "tunnel.h" void CPlatformMemoryYamlInfo::reset(){ int i; @@ -296,6 +297,10 @@ void operator >> (const YAML::Node& node, CMacYamlInfo & mac_info) { if (! utl_yaml_read_uint16(node, "vlan", mac_info.m_vlan, 0, 0xfff)) { mac_info.m_vlan = 0; } + + if (node.FindValue("tunnel")) { + mac_info.m_tunnel = Tunnel::Parse(node["tunnel"]); + } } void operator >> (const YAML::Node& node, CPlatformMemoryYamlInfo & plat_info) { diff --git a/src/platform_cfg.h b/src/platform_cfg.h index f9683c3656..0e20b8758c 100755 --- a/src/platform_cfg.h +++ b/src/platform_cfg.h @@ -96,15 +96,22 @@ const std::string * get_mbuf_names(void); */ - +class Tunnel; struct CMacYamlInfo { +public: std::vector m_dest_base; std::vector m_src_base; + Tunnel* m_tunnel; uint32_t m_def_gw; uint32_t m_ip; uint32_t m_mask; uint16_t m_vlan; + +public: + CMacYamlInfo() { + m_tunnel = NULL; + } void Dump(FILE *fd); void copy_dest(char *p); diff --git a/src/trex_global.h b/src/trex_global.h index 62be4fee00..16cf6a8c15 100644 --- a/src/trex_global.h +++ b/src/trex_global.h @@ -464,11 +464,13 @@ struct CMacAddrCfg { memset(u.m_data, 0, sizeof(u.m_data)); u.m_mac.dest[3] = 1; u.m_mac.is_set = 0; + m_tunnel = NULL; } union { mac_align_t m_mac; uint8_t m_data[16]; } u; + Tunnel* m_tunnel; } __rte_cache_aligned; class CPerPortIPCfg { diff --git a/src/tunnel.cpp b/src/tunnel.cpp new file mode 100644 index 0000000000..60445e3c00 --- /dev/null +++ b/src/tunnel.cpp @@ -0,0 +1,81 @@ +#include +#include + +#include "common/c_common.h" +#include "utl_yaml.h" +#include "trex_global.h" + +#include "gtpu.h" +#include "tunnel.h" + +void Tunnel::InstallRxCallback(uint16_t port_id, uint16_t queue) +{ + Tunnel *t = CGlobalInfo::m_options.m_mac_addr[port_id].m_tunnel; + if (!t) { + return; + } + + if (NULL == rte_eth_add_rx_callback(port_id, queue, Tunnel::RxCallback, (void *)t)) { + printf("failed to install RX callback at %u:%u.\n", port_id, queue); + return; + } + printf("installed RX callback at %u:%u.\n", port_id, queue); +} + +void Tunnel::InstallTxCallback(uint16_t port_id, uint16_t queue) +{ + Tunnel *t = CGlobalInfo::m_options.m_mac_addr[port_id].m_tunnel; + if (!t) { + return; + } + + if (NULL == rte_eth_add_tx_callback(port_id, queue, Tunnel::TxCallback, (void *)t)) { + printf("failed to install TX callback at %u:%u.\n", port_id, queue); + return; + } + printf("installed TX callback at %u:%u.\n", port_id, queue); +} + +uint16_t Tunnel::RxCallback(uint16_t port_id, uint16_t queue, + struct rte_mbuf *pkts[], uint16_t nb_pkts, uint16_t max_pkts, + void *user_param) +{ + Tunnel *t = (Tunnel *)user_param; + if (!t) { + return nb_pkts; + } + for (uint16_t i = 0; i < nb_pkts; i++) { + rte_mbuf * pkt = pkts[i]; + t->Decap(pkt); + } + return nb_pkts; +} + +uint16_t Tunnel::TxCallback(uint16_t port_id, uint16_t queue, + struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param) +{ + Tunnel *t = (Tunnel *)user_param; + if (!t) { + return nb_pkts; + } + for (uint16_t i = 0; i < nb_pkts; i++) { + rte_mbuf * pkt = pkts[i]; + t->Encap(pkt); + } + return nb_pkts; +} + +Tunnel* Tunnel::Parse(YAML::Node const& node) +{ + if (node.FindValue("type")) { + std::string type; + node["type"] >> type; + if (type == "gtpu") { + return static_cast(new GTPU(node)); + } else { + ASSERT_MSG(false, "Unknown tunnel type."); + } + } + return NULL; +} + diff --git a/src/tunnel.h b/src/tunnel.h new file mode 100644 index 0000000000..d6a5206aa0 --- /dev/null +++ b/src/tunnel.h @@ -0,0 +1,26 @@ +#ifndef _TUNNEL_H_ +#define _TUNNEL_H_ + +class Tunnel { +public: + virtual ~Tunnel() {} + + virtual int Encap(struct rte_mbuf *pkt) { return 0; } + virtual int Decap(struct rte_mbuf *pkt) { return 0; } + + static Tunnel* Parse(YAML::Node const&); + + static void InstallRxCallback(uint16_t port_id, uint16_t queue); + + static void InstallTxCallback(uint16_t port_id, uint16_t queue); + +private: + static uint16_t RxCallback(uint16_t port_id, uint16_t queue, + struct rte_mbuf *pkts[], uint16_t nb_pkts, uint16_t max_pkts, + void *user_param); + + static uint16_t TxCallback(uint16_t port_id, uint16_t queue, + struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param); +}; + +#endif