#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/queue.h>
#include <getopt.h>
#include <signal.h>
#include <inttypes.h>
#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
#define NB_MBUFS 64*1024
#define MBUF_CACHE_SIZE 256
#define PKT_BURST 32
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define PARAM_PROC_ID "proc-id"
#define PARAM_NUM_PROCS "num-procs"
struct lcore_ports{
unsigned start_port;
unsigned num_ports;
};
struct port_stats{
unsigned rx;
unsigned tx;
unsigned drop;
static int proc_id = -1;
static unsigned num_procs = 0;
static uint16_t ports[RTE_MAX_ETHPORTS];
static unsigned num_ports = 0;
static struct lcore_ports lcore_ports[RTE_MAX_LCORE];
static struct port_stats pstats[RTE_MAX_ETHPORTS];
static void
smp_usage(const char *prgname, const char *errmsg)
{
printf("\nError: %s\n",errmsg);
printf("\n%s [EAL options] -- -p <port mask> "
"--"PARAM_NUM_PROCS" <n>"
" --"PARAM_PROC_ID" <id>\n"
"-p : a hex bitmask indicating what ports are to be used\n"
"--num-procs: the number of processes which will be used\n"
"--proc-id : the id of the current process (id < num-procs)\n"
"\n",
prgname);
exit(1);
}
static void
print_stats(int signum)
{
unsigned i;
printf("\nExiting on signal %d\n\n", signum);
for (i = 0; i < num_ports; i++){
const uint8_t p_num = ports[i];
printf("Port %u: RX - %u, TX - %u, Drop - %u\n", (unsigned)p_num,
pstats[p_num].rx, pstats[p_num].tx, pstats[p_num].drop);
}
exit(0);
}
static int
smp_parse_args(int argc, char **argv)
{
int opt, ret;
char **argvopt;
int option_index;
uint16_t i, port_mask = 0;
char *prgname = argv[0];
static struct option lgopts[] = {
{PARAM_NUM_PROCS, 1, 0, 0},
{PARAM_PROC_ID, 1, 0, 0},
{NULL, 0, 0, 0}
};
argvopt = argv;
while ((opt = getopt_long(argc, argvopt, "p:", \
lgopts, &option_index)) != EOF) {
switch (opt) {
case 'p':
port_mask = strtoull(optarg, NULL, 16);
break;
case 0:
if (strncmp(lgopts[option_index].name, PARAM_NUM_PROCS, 8) == 0)
num_procs = atoi(optarg);
else if (strncmp(lgopts[option_index].name, PARAM_PROC_ID, 7) == 0)
proc_id = atoi(optarg);
break;
default:
smp_usage(prgname, "Cannot parse all command-line arguments\n");
}
}
if (optind >= 0)
argv[optind-1] = prgname;
if (proc_id < 0)
smp_usage(prgname, "Invalid or missing proc-id parameter\n");
smp_usage(prgname, "Invalid or missing num-procs parameter\n");
if (port_mask == 0)
smp_usage(prgname, "Invalid or missing port mask\n");
if(port_mask & (1 << i))
ports[num_ports++] = (uint8_t)i;
ret = optind-1;
optind = 1;
return ret;
}
static inline int
smp_port_init(uint16_t port,
struct rte_mempool *mbuf_pool,
uint16_t num_queues)
{
.split_hdr_size = 0,
.offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM,
},
.rx_adv_conf = {
.rss_conf = {
.rss_key = NULL,
.rss_hf = RTE_ETH_RSS_IP,
},
},
.txmode = {
}
};
const uint16_t rx_rings = num_queues, tx_rings = num_queues;
int retval;
uint16_t q;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
uint64_t rss_hf_tmp;
return 0;
return -1;
printf("# Initialising port %u... ", port);
fflush(stdout);
if (retval != 0) {
printf("Error during getting device (port %u) info: %s\n",
port, strerror(-retval));
return retval;
}
printf("Port %u modified RSS hash function based on hardware support,"
"requested:%#"PRIx64" configured:%#"PRIx64"\n",
port,
rss_hf_tmp,
}
if (retval == -EINVAL) {
printf("Port %u configuration failed. Re-attempting with HW checksum disabled.\n",
port);
}
if (retval == -ENOTSUP) {
printf("Port %u configuration failed. Re-attempting with HW RSS disabled.\n",
port);
}
if (retval < 0)
return retval;
if (retval < 0)
return retval;
for (q = 0; q < rx_rings; q ++) {
&rxq_conf,
mbuf_pool);
if (retval < 0)
return retval;
}
for (q = 0; q < tx_rings; q ++) {
&txq_conf);
if (retval < 0)
return retval;
}
if (retval != 0)
return retval;
if (retval < 0)
return retval;
return 0;
}
static void
assign_ports_to_cores(void)
{
const unsigned port_pairs = num_ports / 2;
const unsigned pairs_per_lcore = port_pairs / lcores;
unsigned extra_pairs = port_pairs % lcores;
unsigned ports_assigned = 0;
unsigned i;
lcore_ports[i].start_port = ports_assigned;
lcore_ports[i].num_ports = pairs_per_lcore * 2;
if (extra_pairs > 0) {
lcore_ports[i].num_ports += 2;
extra_pairs--;
}
ports_assigned += lcore_ports[i].num_ports;
}
}
static int
{
const unsigned start_port = lcore_ports[id].start_port;
const unsigned end_port = start_port + lcore_ports[id].num_ports;
const uint16_t q_id = (uint16_t)proc_id;
unsigned p, i;
char msgbuf[256];
int msgbufpos = 0;
if (start_port == end_port){
printf("Lcore %u has nothing to do\n", id);
return 0;
}
msgbufpos += snprintf(msgbuf, sizeof(msgbuf) - msgbufpos,
"Lcore %u using ports ", id);
for (p = start_port; p < end_port; p++){
msgbufpos += snprintf(msgbuf + msgbufpos, sizeof(msgbuf) - msgbufpos,
"%u ", (unsigned)ports[p]);
}
printf("%s\n", msgbuf);
printf("lcore %u using queue %u of each port\n", id, (unsigned)q_id);
for (;;) {
for (p = start_port; p < end_port; p++) {
const uint8_t src = ports[p];
const uint8_t dst = ports[p ^ 1];
if (rx_c == 0)
continue;
pstats[src].rx += rx_c;
pstats[dst].tx += tx_c;
if (tx_c != rx_c) {
pstats[dst].drop += (rx_c - tx_c);
for (i = tx_c; i < rx_c; i++)
}
}
}
}
static void
check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
{
#define CHECK_INTERVAL 100
#define MAX_CHECK_TIME 90
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
int ret;
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
all_ports_up = 1;
for (portid = 0; portid < port_num; portid++) {
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
if (ret < 0) {
all_ports_up = 0;
if (print_flag == 1)
printf("Port %u link get failed: %s\n",
continue;
}
if (print_flag == 1) {
sizeof(link_status_text), &link);
printf("Port %d %s\n", portid,
link_status_text);
continue;
}
all_ports_up = 0;
break;
}
}
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
}
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
int
main(int argc, char **argv)
{
static const char *_SMP_MBUF_POOL = "SMP_MBUF_POOL";
int ret;
unsigned i;
signal(SIGINT, print_stats);
signal(SIGTERM, print_stats);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot init EAL\n");
argc -= ret;
argv += ret;
rte_exit(EXIT_FAILURE,
"No Ethernet ports - bye\n");
smp_parse_args(argc, argv);
mp = (proc_type == RTE_PROC_SECONDARY) ?
MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
if (mp == NULL)
rte_exit(EXIT_FAILURE,
"Cannot get memory pool for buffers\n");
if (num_ports & 1)
rte_exit(EXIT_FAILURE,
"Application must use an even number of ports\n");
for(i = 0; i < num_ports; i++){
if(proc_type == RTE_PROC_PRIMARY)
if (smp_port_init(ports[i], mp, (uint16_t)num_procs) < 0)
rte_exit(EXIT_FAILURE,
"Error initialising ports\n");
}
if (proc_type == RTE_PROC_PRIMARY)
check_all_ports_link_status((uint8_t)num_ports, (~0x0));
assign_ports_to_cores();
RTE_LOG(INFO, APP,
"Finished Process Init.\n");
return 0;
}