stable, merging to master branch

This commit is contained in:
oscar 2020-11-16 20:07:50 -05:00
parent cadd5a21a4
commit c34be253f7
5 changed files with 225 additions and 129 deletions

View File

@ -1,5 +1,11 @@
cmake_minimum_required(VERSION 3.0)
find_program(CC_GCC gcc)
find_program(CXX_GCC g++)
set(CMAKE_C_COMPILER ${CC_GCC})
set(CMAKE_CXX_COMPILER ${CXX_GCC})
project(khat)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
@ -13,7 +19,7 @@ include_directories(${dpdk_INCLUDE_DIRS})
add_executable(khat khat/khat.cc)
add_executable(cat cat/cat.cc)
set(LINK_LIBS ${dpdk_LIBRARIES} pthread numa)
set(LINK_LIBS ${dpdk_LIBRARIES} pthread)
target_link_libraries(khat ${LINK_LIBS})
target_compile_options(khat PRIVATE ${CC_FLAGS})

View File

@ -1,3 +1,4 @@
#include <cstdio>
#include <ctime>
#include <netinet/in.h>
#include <rte_config.h>
@ -15,15 +16,23 @@
#include <fstream>
#include <unistd.h>
#include "ntrlog.h"
#include "pkt.h"
#include "rte_byteorder.h"
constexpr unsigned int MBUF_MAX_COUNT = 1024;
constexpr unsigned int MBUF_CACHE_SIZE = 256;
// init NTRLOG
NTR_DECL_IMPL;
constexpr unsigned int MBUF_MAX_COUNT = 8191;
constexpr unsigned int MBUF_CACHE_SIZE = 250;
constexpr unsigned int RX_RING_SIZE = 1024;
constexpr unsigned int TX_RING_SIZE = 1024;
constexpr unsigned int RX_RING_NUM = 1;
constexpr unsigned int TX_RING_NUM = 1;
constexpr unsigned int BURST_SIZE = 4;
constexpr unsigned int BURST_SIZE = 32;
static const struct rte_eth_conf port_conf_default{};
struct datapt{
uint64_t server_proc = 0;
@ -58,11 +67,12 @@ rx_calc_latency(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
pkt_data = check_valid_packet(pkts[i]);
if (pkt_data == NULL) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "rx_calc_latency: ignoring invalid packet 0x%p.", (void*)pkts[i]);
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG, "rx_calc_latency: ignoring invalid packet 0x%p.\n", (void*)pkts[i]);
continue;
}
pkt_data->clt_ts_rx = htonll(now);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "rx_calc_latency: tagged packet %p with %llu.\n", (void*)pkts[i], now);
pkt_data->clt_ts_rx = rte_cpu_to_be_64(now);
}
return nb_pkts;
@ -80,11 +90,12 @@ tx_add_timestamp(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
pkt_data = check_valid_packet(pkts[i]);
if (pkt_data == NULL) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "tx_add_timestamp: ignoring invalid packet 0x%p.", (void*)pkts[i]);
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG, "tx_add_timestamp: ignoring invalid packet 0x%p.\n", (void*)pkts[i]);
continue;
}
pkt_data->clt_ts_tx = htonll(now);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "tx_add_timestamp: tagged packet %p with %llu.\n", (void*)pkts[i], now);
pkt_data->clt_ts_tx = rte_cpu_to_be_64(now);
}
return nb_pkts;
@ -104,25 +115,29 @@ locore_main(void * _unused __rte_unused)
int state = STATE_SEND;
if (rte_eth_dev_socket_id(options.s_portid) > 0 && rte_eth_dev_socket_id(options.s_portid) != (int)rte_socket_id()) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "locore_main: WARNING, port %d is on remote NUMA node to "
ntr(NTR_DEP_USER1, NTR_LEVEL_WARNING, "locore_main: WARNING, port %d is on remote NUMA node to "
"polling thread.\n\tPerformance will "
"not be optimal.\n", options.s_portid);
}
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1, "locore_main: core %d sending packets... [Ctrl+C to quit]\n", core_id);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "locore_main: core %d running...\n", core_id);
tx_buf = rte_pktmbuf_alloc(options.s_mbuf_pool);
if (tx_buf == NULL) {
rte_exit(EXIT_FAILURE, "cannot allocate tx_buf");
rte_exit(EXIT_FAILURE, "cannot allocate tx_buf\n");
}
tx_buf->l2_len = sizeof(struct rte_ether_hdr);
tx_buf->nb_segs = 1;
pkt_data = (struct packet_data *)rte_pktmbuf_append(tx_buf, sizeof(struct packet_data));
if (pkt_data == NULL) {
rte_exit(EXIT_FAILURE, "cannot allocate space for packet_data in mbuf");
rte_exit(EXIT_FAILURE, "cannot allocate space for packet_data in mbuf\n");
}
// construct the packet ether type
pkt_data->eth_hdr.ether_type = 0x1234;
pkt_data->magic = rte_cpu_to_be_32(ETHER_FRAME_MAGIC);
pkt_data->eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
rte_ether_addr_copy(&options.server_mac, &pkt_data->eth_hdr.d_addr);
rte_ether_addr_copy(&options.s_host_mac, &pkt_data->eth_hdr.s_addr);
@ -136,18 +151,18 @@ locore_main(void * _unused __rte_unused)
struct packet_data * each = check_valid_packet(rx_bufs[i]);
if (each == NULL) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "locore_main: ignoring invalid packet 0x%p.", (void*)rx_bufs[i]);
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG, "locore_main: ignoring invalid packet %p.\n", (void*)rx_bufs[i]);
continue;
}
if (each->epoch == epoch) {
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1, "locore_main: received packet 0x%p for epoch %d", (void*)rx_bufs[i], epoch);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "locore_main: received packet %p for epoch %d\n", (void*)rx_bufs[i], epoch);
if (options.s_record.load()) {
// keep statistics
struct datapt * dpt = new datapt;
dpt->rtt = ntohll(pkt_data->clt_ts_rx) - ntohll(pkt_data->clt_ts_tx);
dpt->server_proc = ntohll(pkt_data->srv_ts_tx) - ntohll(pkt_data->srv_ts_rx);
dpt->rtt = rte_be_to_cpu_64(each->clt_ts_rx) - rte_be_to_cpu_64(each->clt_ts_tx);
dpt->server_proc = rte_be_to_cpu_64(each->srv_ts_tx) - rte_be_to_cpu_64(each->srv_ts_rx);
options.s_stats.push_back(dpt);
}
@ -156,7 +171,7 @@ locore_main(void * _unused __rte_unused)
epoch++;
break;
} else {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "locore_main: ignoring packet 0x%p with invalid epoch %d.", (void*)rx_bufs[i], epoch);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "locore_main: ignoring packet 0x%p with invalid epoch %d.\n", (void*)rx_bufs[i], epoch);
}
}
}
@ -164,19 +179,20 @@ locore_main(void * _unused __rte_unused)
if (state == STATE_SEND) {
// set new epoch
pkt_data->epoch = epoch;
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1, "locore_main: sending packet 0x%p with epoch %d", (void*)tx_buf, epoch);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "locore_main: sending packet %p with epoch %d\n", (void*)tx_buf, epoch);
const uint16_t nb_tx = rte_eth_tx_burst(options.s_portid, 0, &tx_buf, 1);
if (nb_tx < 1) {
rte_exit(EXIT_FAILURE, "failed to send packet 0x%p, epoch %d", (void*)tx_buf, epoch);
rte_exit(EXIT_FAILURE, "failed to send packet 0x%p, epoch %d\n", (void*)tx_buf, epoch);
}
state = STATE_RECV;
}
}
rte_pktmbuf_free(tx_buf);
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1, "locore_main: core %d successfully stopped.", core_id);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "locore_main: core %d successfully stopped.\n", core_id);
return 0;
}
@ -185,8 +201,9 @@ static int
port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
{
struct rte_eth_dev_info dev_info;
struct rte_eth_conf port_conf;
struct rte_eth_conf port_conf = port_conf_default;
struct rte_eth_txconf txconf;
struct rte_eth_rxconf rxconf;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
@ -203,10 +220,7 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
if(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
if(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM)
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_IPV4_CKSUM;
if(dev_info.rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM)
port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_IPV4_CKSUM;
port_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MAX_LEN;
/* Configure the Ethernet device. */
ret = rte_eth_dev_configure(portid, RX_RING_NUM, TX_RING_NUM, &port_conf);
@ -218,6 +232,8 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
return ret;
/* Allocate and set up 1 RX queue per Ethernet port. */
rxconf = dev_info.default_rxconf;
rxconf.offloads = port_conf.rxmode.offloads;
for (uint32_t i = 0; i < RX_RING_NUM; i++) {
ret = rte_eth_rx_queue_setup(portid, i, nb_rxd, rte_eth_dev_socket_id(portid), NULL, mbuf_pool);
if (ret < 0)
@ -242,16 +258,9 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
ret = rte_eth_macaddr_get(portid, &addr);
if (ret != 0)
return ret;
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
" %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
portid,
addr.addr_bytes[0], addr.addr_bytes[1],
addr.addr_bytes[2], addr.addr_bytes[3],
addr.addr_bytes[4], addr.addr_bytes[5]);
/* Enable RX in promiscuous mode for the Ethernet device. */
ret = rte_eth_promiscuous_enable(portid);
ret = rte_eth_promiscuous_enable(portid);
if (ret != 0)
return ret;
@ -261,41 +270,59 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
return 0;
}
static void dump_options()
{
fprintf(stdout, "Configuration:\n" \
" run time = %d\n" \
" warmup time = %d\n" \
" output file = %s\n" \
" server MAC = %x:%x:%x:%x:%x:%x\n",
options.run_time,
options.warmup_time,
options.output,
options.server_mac.addr_bytes[0],
options.server_mac.addr_bytes[1],
options.server_mac.addr_bytes[2],
options.server_mac.addr_bytes[3],
options.server_mac.addr_bytes[4],
options.server_mac.addr_bytes[5]);
}
static void usage()
{
fprintf(stdout, "Usage:\n \
-v: verbose mode\n \
-h: display the information\n");
-h: display the information\n\n");
}
int main(int argc, char* argv[])
{
unsigned int nb_ports;
struct rte_mempool *mbuf_pool;
struct rte_mempool *mbuf_pool, *mbuf_pool_pkt;
std::ofstream log_file;
// init dpdk
int ret = rte_eal_init(argc, argv);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "rte_eal_init failed!");
rte_exit(EXIT_FAILURE, "rte_eal_init failed!\n");
}
argc -= ret;
argv += ret;
// set warning level
rte_log_set_level(RTE_LOGTYPE_USER1, RTE_LOG_WARNING);
ntr_set_level(NTR_DEP_USER1, NTR_LEVEL_WARNING);
{
int c;
// parse arguments
while((c = getopt(argc, argv, "hvo:t:T:s:")) != -1) {
switch (c) {
case 'v':
rte_log_set_level(RTE_LOGTYPE_USER1, RTE_LOG_INFO);
ntr_set_level(NTR_DEP_USER1, ntr_get_level(NTR_DEP_USER1) + 1);
break;
case 's':
if (rte_ether_unformat_addr(optarg, &options.server_mac) == -1) {
rte_exit(EXIT_FAILURE, "cannot parse %s as mac address.", optarg);
rte_exit(EXIT_FAILURE, "cannot parse %s as mac address.\n", optarg);
}
break;
case 't':
@ -313,7 +340,7 @@ int main(int argc, char* argv[])
break;
default:
usage();
rte_exit(EXIT_FAILURE, "unknown argument: %c", c);
rte_exit(EXIT_FAILURE, "unknown argument: %c\n", c);
break;
}
}
@ -322,36 +349,41 @@ int main(int argc, char* argv[])
// open log file for writing
log_file.open(options.output, std::ofstream::out);
if (!log_file) {
rte_exit(EXIT_FAILURE, "failed to open log file");
rte_exit(EXIT_FAILURE, "failed to open log file %s\n", options.output);
}
nb_ports = rte_eth_dev_count_avail();
if (nb_ports < 2 || (nb_ports & 1)) {
rte_exit(EXIT_FAILURE, "number of ports must be even");
if (nb_ports == 0) {
rte_exit(EXIT_FAILURE, "number of ports must be > 0\n");
}
// create a mbuf memory pool on the socket
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", MBUF_MAX_COUNT * nb_ports, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == nullptr) {
rte_exit(EXIT_FAILURE, "cannot create mbuf pool");
rte_exit(EXIT_FAILURE, "cannot create mbuf pool\n");
}
options.s_mbuf_pool = mbuf_pool;
mbuf_pool_pkt = rte_pktmbuf_pool_create("MBUF_POOL_PKT", MBUF_MAX_COUNT * nb_ports, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool_pkt == nullptr) {
rte_exit(EXIT_FAILURE, "cannot create mbuf pool\n");
}
options.s_mbuf_pool = mbuf_pool_pkt;
uint16_t portid = rte_eth_find_next(0);
if (portid == RTE_MAX_ETHPORTS) {
rte_exit(EXIT_FAILURE, "cannot find an available port");
rte_exit(EXIT_FAILURE, "cannot find an available port\n");
}
options.s_portid = portid;
if (port_init(portid, mbuf_pool) != 0) {
rte_exit(EXIT_FAILURE, "cannot init port %d", portid);
rte_exit(EXIT_FAILURE, "cannot init port %d\n", portid);
}
if (rte_eth_macaddr_get(portid, &options.s_host_mac) != 0) {
rte_exit(EXIT_FAILURE, "cannot get mac address of port %d", portid);
rte_exit(EXIT_FAILURE, "cannot get mac address of port %d\n", portid);
}
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1, "Configured port %d with mac addr %x-%x-%x-%x-%x-%x", portid,
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "Configured port %d with mac addr %x:%x:%x:%x:%x:%x\n", portid,
options.s_host_mac.addr_bytes[0],
options.s_host_mac.addr_bytes[1],
options.s_host_mac.addr_bytes[2],
@ -359,9 +391,11 @@ int main(int argc, char* argv[])
options.s_host_mac.addr_bytes[4],
options.s_host_mac.addr_bytes[5]);
dump_options();
uint16_t core_id = rte_get_next_lcore(0, true, false);
if (rte_eal_remote_launch(locore_main, NULL, core_id) != 0) {
rte_exit(EXIT_FAILURE, "failed to launch function on locore");
rte_exit(EXIT_FAILURE, "failed to launch function on locore\n");
}
// poor man's timer
@ -383,7 +417,7 @@ int main(int argc, char* argv[])
}
if (rte_eal_wait_lcore(core_id) < 0)
rte_exit(EXIT_FAILURE, "failed to wait for job completion");
rte_exit(EXIT_FAILURE, "failed to wait for job completion\n");
// dump stats
for (auto it = std::begin(options.s_stats); it != std::end(options.s_stats); ++it) {

61
inc/ntrlog.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include <stdio.h>
#define NTR_LEVEL_NONE (0)
#define NTR_LEVEL_ERROR (1)
#define NTR_LEVEL_WARNING (2)
#define NTR_LEVEL_INFO (3)
#define NTR_LEVEL_DEBUG (4)
#define NTR_LEVEL_DEFAULT (NTR_LEVEL_WARNING)
#define NTR_DEP_NTR (0)
#define NTR_DEP_USER1 (1)
#define NTR_DEP_USER2 (2)
#define NTR_DEP_USER3 (3)
#define NTR_DEP_USER4 (4)
#define NTR_DEP_USER5 (5)
#define NTR_DEP_MAX (NTR_DEP_USER5 + 1)
#define NTR_DECL_IMPL \
int ntr_log_levels[NTR_DEP_MAX] = {NTR_LEVEL_DEFAULT}; \
FILE * ntr_out = stdout
extern int ntr_log_levels[];
extern FILE * ntr_out;
static inline
void ntr(int dep, int level, const char * fmt, ...)
{
va_list vl;
va_start(vl, fmt);
if (dep < NTR_DEP_MAX && level <= ntr_log_levels[dep]) {
vfprintf(ntr_out, fmt, vl);
}
va_end(vl);
}
static inline
void ntr_set_level(int dep, int level)
{
if (dep < NTR_DEP_MAX) {
ntr_log_levels[dep] = level;
}
}
static inline
void ntr_set_output(FILE * f)
{
if (f != NULL) {
ntr_out = f;
}
}
static inline
int ntr_get_level(int dep)
{
if (dep < NTR_DEP_MAX) {
return ntr_log_levels[dep];
}
return 0;
}

View File

@ -1,15 +1,16 @@
#pragma once
#include <rte_byteorder.h>
#include <rte_ip.h>
#include <stdint.h>
#include <rte_ether.h>
#include <unistd.h>
#include <netinet/in.h>
constexpr static uint16_t ETHER_FRAME_MAGIC = 0x1234;
constexpr static uint32_t ETHER_FRAME_MAGIC = 0xDCDCE5E5;
struct packet_data
{
struct rte_ether_hdr eth_hdr;
uint32_t magic;
uint32_t epoch;
uint64_t clt_ts_tx;
uint64_t clt_ts_rx;
@ -28,27 +29,9 @@ struct packet_data * check_valid_packet(struct rte_mbuf * pkt)
pkt_data = rte_pktmbuf_mtod(pkt, struct packet_data *);
if (ntohs(pkt_data->eth_hdr.ether_type) != ETHER_FRAME_MAGIC) {
return NULL;
if (rte_be_to_cpu_16(pkt_data->eth_hdr.ether_type) == RTE_ETHER_TYPE_IPV4 && rte_be_to_cpu_32(pkt_data->magic) == ETHER_FRAME_MAGIC) {
return pkt_data;
}
return pkt_data;
}
static inline uint64_t htonll(uint64_t x)
{
#if __BIG_ENDIAN__
return x;
#else
return ((uint64_t)htonl((x) & 0xFFFFFFFFLL) << 32) | htonl((x) >> 32);
#endif
}
static inline uint64_t ntohll(uint64_t x)
{
#if __BIG_ENDIAN__
return x;
#else
return ((uint64_t)ntohl((x) & 0xFFFFFFFFLL) << 32) | ntohl((x) >> 32);
#endif
return NULL;
}

View File

@ -1,3 +1,4 @@
#include <cstdio>
#include <cstdlib>
#include <rte_common.h>
#include <rte_eal.h>
@ -5,20 +6,27 @@
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <rte_byteorder.h>
#include <rte_config.h>
#include <rte_ether.h>
#include <rte_launch.h>
#include <atomic>
#include <unistd.h>
#include "pkt.h"
#include "rte_launch.h"
#include "rte_log.h"
#include "ntrlog.h"
constexpr unsigned int MBUF_MAX_COUNT = 1024;
constexpr unsigned int MBUF_CACHE_SIZE = 256;
NTR_DECL_IMPL;
constexpr unsigned int MBUF_MAX_COUNT = 8191;
constexpr unsigned int MBUF_CACHE_SIZE = 250;
constexpr unsigned int RX_RING_SIZE = 1024;
constexpr unsigned int TX_RING_SIZE = 1024;
constexpr unsigned int RX_RING_NUM = 1;
constexpr unsigned int TX_RING_NUM = 1;
constexpr unsigned int BURST_SIZE = 4;
constexpr unsigned int BURST_SIZE = 32;
static const struct rte_eth_conf port_conf_default{};
struct options_t {
//states
@ -34,16 +42,16 @@ rx_add_timestamp(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
{
uint64_t now = rte_rdtsc();
struct packet_data * pkt_data;
for (int i = 0; i < nb_pkts; i++) {
pkt_data = check_valid_packet(pkts[i]);
if (pkt_data == NULL) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "rx_add_timestamp: ignoring invalid packet 0x%p.", (void*)pkts[i]);
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG, "rx_add_timestamp: ignoring invalid packet %p.\n", (void*)pkts[i]);
continue;
}
pkt_data->srv_ts_rx = htonll(now);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "rx_add_timestamp: tagged packet %p with %llu.\n", (void*)pkts[i], now);
pkt_data->srv_ts_rx = rte_cpu_to_be_64(now);
}
return nb_pkts;
@ -61,11 +69,12 @@ tx_calc_latency(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
pkt_data = check_valid_packet(pkts[i]);
if (pkt_data == NULL) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "tx_calc_latency: ignoring invalid packet 0x%p.", (void*)pkts[i]);
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG, "tx_calc_latency: ignoring invalid packet %p.\n", (void*)pkts[i]);
continue;
}
pkt_data->srv_ts_tx = htonll(now);
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "tx_calc_latency: tagged packet %p with %llu.\n", (void*)pkts[i], now);
pkt_data->srv_ts_tx = rte_cpu_to_be_64(now);
}
return nb_pkts;
@ -80,32 +89,32 @@ locore_main(void * _unused __rte_unused)
struct rte_ether_addr eth_addr;
uint32_t core_id = rte_lcore_id();
if (rte_eth_dev_socket_id(options.s_portid) > 0 && rte_eth_dev_socket_id(options.s_portid) != (int)rte_socket_id()) {
ntr(NTR_DEP_USER1, NTR_LEVEL_WARNING, "locore_main: WARNING, port %d is on remote NUMA node to "
"polling thread.\n\tPerformance will "
"not be optimal.\n", options.s_portid);
}
if (rte_eth_dev_socket_id(options.s_portid) > 0 && rte_eth_dev_socket_id(options.s_portid) != (int)rte_socket_id()) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "locore_main: WARNING, port %d is on remote NUMA node to "
"polling thread.\n\tPerformance will "
"not be optimal.\n", options.s_portid);
}
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "locore_main: core %d running.\n", core_id);
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1, "locore_main: core %d forwarding packets. [Ctrl+C to quit]\n", core_id);
while(1) {
while(true) {
uint16_t nb_tx = 0;
const uint16_t nb_rx = rte_eth_rx_burst(options.s_portid, 0, bufs, BURST_SIZE);
if (nb_rx == 0)
continue;
if (nb_rx == 0) {
continue;
}
for(int i = 0; i < nb_rx; i++) {
pkt_data = check_valid_packet(bufs[i]);
if (pkt_data == NULL) {
rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1, "locore_main: core %d skipping invalid packet %p.", core_id, (void*)bufs[i]);
ntr(NTR_DEP_USER1, NTR_LEVEL_DEBUG, "locore_main: core %d skipping invalid packet %p.\n", core_id, (void*)bufs[i]);
continue;
}
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1,"locore_main: core %d rx packet from %x-%x-%x-%x-%x-%x", core_id,
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "locore_main: core %d rx packet %p from %x:%x:%x:%x:%x:%x\n", core_id, (void*)bufs[i],
pkt_data->eth_hdr.s_addr.addr_bytes[0],
pkt_data->eth_hdr.s_addr.addr_bytes[1],
pkt_data->eth_hdr.s_addr.addr_bytes[2],
@ -125,7 +134,7 @@ locore_main(void * _unused __rte_unused)
const uint16_t nb_tx_succ = rte_eth_tx_burst(options.s_portid, 0, tx_bufs, nb_tx);
// cleanup unsent packets
if (nb_tx_succ < nb_tx) {
rte_exit(EXIT_FAILURE, "locore_main: failed to send some packets.");
rte_exit(EXIT_FAILURE, "locore_main: failed to send some packets.\n");
// rte_log(RTE_LOG_WARNING, RTE_LOGTYPE_USER1,"locore_main: core %d some packets failed to queue to tx - expected: %d sent: %d", core_id, nb_tx, nb_tx_succ);
// for (uint16_t buf = nb_tx_succ; buf < nb_tx; buf++)
// rte_pktmbuf_free(tx_bufs[buf]);
@ -139,12 +148,12 @@ static int
port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
{
struct rte_eth_dev_info dev_info;
struct rte_eth_conf port_conf;
struct rte_eth_conf port_conf = port_conf_default;
struct rte_eth_txconf txconf;
struct rte_eth_rxconf rxconf;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
port_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MAX_LEN;
if(!rte_eth_dev_is_valid_port(portid)) {
return -1;
@ -157,10 +166,7 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
if(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
if(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM)
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_IPV4_CKSUM;
if(dev_info.rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM)
port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_IPV4_CKSUM;
port_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MAX_LEN;
/* Configure the Ethernet device. */
ret = rte_eth_dev_configure(portid, RX_RING_NUM, TX_RING_NUM, &port_conf);
@ -172,8 +178,9 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
return ret;
/* Allocate and set up 1 RX queue per Ethernet port. */
rxconf = dev_info.default_rxconf;
for (uint32_t i = 0; i < RX_RING_NUM; i++) {
ret = rte_eth_rx_queue_setup(portid, i, nb_rxd, rte_eth_dev_socket_id(portid), NULL, mbuf_pool);
ret = rte_eth_rx_queue_setup(portid, i, nb_rxd, rte_eth_dev_socket_id(portid), &rxconf, mbuf_pool);
if (ret < 0)
return ret;
}
@ -197,20 +204,14 @@ port_init(uint16_t portid, struct rte_mempool *mbuf_pool)
if (ret != 0)
return ret;
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
" %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
portid,
addr.addr_bytes[0], addr.addr_bytes[1],
addr.addr_bytes[2], addr.addr_bytes[3],
addr.addr_bytes[4], addr.addr_bytes[5]);
/* Enable RX in promiscuous mode for the Ethernet device. */
ret = rte_eth_promiscuous_enable(portid);
ret = rte_eth_promiscuous_enable(portid);
if (ret != 0)
return ret;
rte_eth_add_tx_callback(portid, 0, tx_calc_latency, NULL);
rte_eth_add_rx_callback(portid, 0, rx_add_timestamp, NULL);
if (rte_eth_add_tx_callback(portid, 0, tx_calc_latency, NULL) == NULL || rte_eth_add_rx_callback(portid, 0, rx_add_timestamp, NULL) == NULL) {
return -1;
}
return 0;
}
@ -230,21 +231,21 @@ int main(int argc, char* argv[])
// init dpdk
int ret = rte_eal_init(argc, argv);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "rte_eal_init failed!");
rte_exit(EXIT_FAILURE, "rte_eal_init failed!\n");
}
argc -= ret;
argv += ret;
// set warning level
rte_log_set_level(RTE_LOGTYPE_USER1, RTE_LOG_WARNING);
ntr_set_level(NTR_DEP_USER1, NTR_LEVEL_WARNING);
{
int c;
// parse arguments
while((c = getopt(argc, argv, "hv")) != -1) {
switch (c) {
case 'v':
rte_log_set_level(RTE_LOGTYPE_USER1, RTE_LOG_INFO);
ntr_set_level(NTR_DEP_USER1, ntr_get_level(NTR_DEP_USER1) + 1);
break;
case 'h':
usage();
@ -259,31 +260,31 @@ int main(int argc, char* argv[])
}
nb_ports = rte_eth_dev_count_avail();
if (nb_ports < 2 || (nb_ports & 1)) {
rte_exit(EXIT_FAILURE, "number of ports must be even");
if (nb_ports == 0) {
rte_exit(EXIT_FAILURE, "number of ports must be > 0\n");
}
// create a mbuf memory pool on the socket
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", MBUF_MAX_COUNT * nb_ports, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == nullptr) {
rte_exit(EXIT_FAILURE, "cannot create mbuf pool");
rte_exit(EXIT_FAILURE, "cannot create mbuf pool\n");
}
uint16_t portid = rte_eth_find_next(0);
if (portid == RTE_MAX_ETHPORTS) {
rte_exit(EXIT_FAILURE, "cannot find an available port");
rte_exit(EXIT_FAILURE, "cannot find an available port\n");
}
options.s_portid = portid;
if (port_init(portid, mbuf_pool) != 0) {
rte_exit(EXIT_FAILURE, "cannot init port %d", portid);
rte_exit(EXIT_FAILURE, "cannot init port %d\n", portid);
}
if (rte_eth_macaddr_get(portid, &options.s_host_mac) != 0) {
rte_exit(EXIT_FAILURE, "cannot get mac address of port %d", portid);
rte_exit(EXIT_FAILURE, "cannot get mac address of port %d\n", portid);
}
rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1, "Configured port %d with mac addr %x-%x-%x-%x-%x-%x", portid,
ntr(NTR_DEP_USER1, NTR_LEVEL_INFO, "Configured port %d with mac addr %x:%x:%x:%x:%x:%x\n", portid,
options.s_host_mac.addr_bytes[0],
options.s_host_mac.addr_bytes[1],
options.s_host_mac.addr_bytes[2],
@ -293,13 +294,24 @@ int main(int argc, char* argv[])
uint16_t lcore_id = rte_get_next_lcore(0, true, false);
if (lcore_id == RTE_MAX_LCORE) {
rte_exit(EXIT_FAILURE, "cannot detect lcores.\n");
}
if (rte_eal_remote_launch(locore_main, NULL, lcore_id) != 0) {
rte_exit(EXIT_FAILURE, "failed to launch function on locore %d", lcore_id);
rte_exit(EXIT_FAILURE, "failed to launch function on locore %d\n", lcore_id);
}
// while(true) {
// struct rte_eth_stats stats;
// rte_eth_stats_get(portid, &stats);
// printf("recv: %d missed: %d err: %d\n",(uint32_t)stats.ipackets, (uint32_t)stats.imissed,(uint32_t)stats.ierrors);
// usleep(1000000);
// }
if (rte_eal_wait_lcore(lcore_id) != 0) {
rte_exit(EXIT_FAILURE, "failed to wait for locore %d", lcore_id);
rte_exit(EXIT_FAILURE, "failed to wait for locore %d\n", lcore_id);
}
// shouldn't get here