#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;
} __attribute__((aligned(RTE_CACHE_LINE_SIZE / 2)));
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
           uint16_t num_queues)
{
                .split_hdr_size = 0,
                .offloads = DEV_RX_OFFLOAD_CHECKSUM,
            },
            .rx_adv_conf = {
                .rss_conf = {
                    .rss_key = NULL,
                    .rss_hf = 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);
    info.default_rxconf.rx_drop_en = 1;
        printf("Port %u modified RSS hash function based on hardware support,"
            "requested:%#"PRIx64" configured:%#"PRIx64"\n",
            rss_hf_tmp,
    }
    if (retval < 0)
        return retval;
    if (retval < 0)
        return retval;
    rxq_conf = info.default_rxconf;
    for (q = 0; q < rx_rings; q ++) {
                &rxq_conf,
                mbuf_pool);
        if (retval < 0)
            return retval;
    }
    txq_conf = info.default_txconf;
    for (q = 0; q < tx_rings; q ++) {
                &txq_conf);
        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;
    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 (print_flag == 1) {
                if (link.link_status)
                    printf(
                    "Port%d Link Up. Speed %u Mbps - %s\n",
                        portid, link.link_speed,
                    ("full-duplex") : ("half-duplex\n"));
                else
                    printf("Port %d Link Down\n", portid);
                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;
}