#include <stdio.h>
#include <getopt.h>
#define APP_MODE_FWD                    0
#define APP_MODE_SRTCM_COLOR_BLIND      1
#define APP_MODE_SRTCM_COLOR_AWARE      2
#define APP_MODE_TRTCM_COLOR_BLIND      3
#define APP_MODE_TRTCM_COLOR_AWARE      4
#define APP_MODE    APP_MODE_SRTCM_COLOR_BLIND
#include "main.h"
#define APP_PKT_FLOW_POS                33
#define APP_PKT_COLOR_POS               5
#if APP_PKT_FLOW_POS > 64 || APP_PKT_COLOR_POS > 64
#error Byte offset needs to be less than 64
#endif
#define NB_MBUF             8192
#define MEMPOOL_CACHE_SIZE  256
        .split_hdr_size = 0,
        .offloads = DEV_RX_OFFLOAD_CHECKSUM,
    },
    .rx_adv_conf = {
        .rss_conf = {
            .rss_key = NULL,
            .rss_hf = ETH_RSS_IP,
        },
    },
    .txmode = {
    },
};
#define NIC_RX_QUEUE_DESC               1024
#define NIC_TX_QUEUE_DESC               1024
#define NIC_RX_QUEUE                    0
#define NIC_TX_QUEUE                    0
#define PKT_RX_BURST_MAX                32
#define PKT_TX_BURST_MAX                32
#define TIME_TX_DRAIN                   200000ULL
static uint16_t port_rx;
static uint16_t port_tx;
static struct rte_mbuf *pkts_rx[PKT_RX_BURST_MAX];
 
    .cbs = 2048,
    .ebs = 2048
};
struct rte_meter_srtcm_profile app_srtcm_profile;
    .pir = 1500000 * 46,
    .cbs = 2048,
    .pbs = 2048
};
struct rte_meter_trtcm_profile app_trtcm_profile;
#define APP_FLOWS_MAX  256
FLOW_METER app_flows[APP_FLOWS_MAX];
static int
app_configure_flow_table(void)
{
    uint32_t i;
    int ret;
        &app_srtcm_params);
    if (ret)
        return ret;
        &app_trtcm_params);
    if (ret)
        return ret;
    for (i = 0; i < APP_FLOWS_MAX; i++) {
        ret = FUNC_CONFIG(&app_flows[i], &PROFILE);
        if (ret)
            return ret;
    }
    return 0;
}
static inline void
app_set_pkt_color(uint8_t *pkt_data, enum policer_action color)
{
    pkt_data[APP_PKT_COLOR_POS] = (uint8_t)color;
}
static inline int
app_pkt_handle(
struct rte_mbuf *pkt, uint64_t time)
{
    uint8_t input_color, output_color;
    uint8_t flow_id = (uint8_t)(pkt_data[APP_PKT_FLOW_POS] & (APP_FLOWS_MAX - 1));
    input_color = pkt_data[APP_PKT_COLOR_POS];
    enum policer_action action;
    
    output_color = (uint8_t) FUNC_METER(&app_flows[flow_id],
        &PROFILE,
        time,
        pkt_len,
    
    action = policer_table[input_color][output_color];
    app_set_pkt_color(pkt_data, action);
    return action;
}
static __attribute__((noreturn)) int
main_loop(__attribute__((unused)) void *dummy)
{
    uint64_t current_time, last_time = rte_rdtsc();
    printf("Core %u: port RX = %d, port TX = %d\n", lcore_id, port_rx, port_tx);
    while (1) {
        uint64_t time_diff;
        int i, nb_rx;
        
        current_time = rte_rdtsc();
        time_diff = current_time - last_time;
        if (
unlikely(time_diff > TIME_TX_DRAIN)) {
 
            
            last_time = current_time;
        }
        
        
        for (i = 0; i < nb_rx; i ++) {
            
            if (app_pkt_handle(pkt, current_time) == DROP)
            else
        }
    }
}
static void
print_usage(const char *prgname)
{
    printf ("%s [EAL options] -- -p PORTMASK\n"
        "  -p PORTMASK: hexadecimal bitmask of ports to configure\n",
        prgname);
}
static int
parse_portmask(const char *portmask)
{
    char *end = NULL;
    unsigned long pm;
    
    pm = strtoul(portmask, &end, 16);
    if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
        return -1;
    if (pm == 0)
        return -1;
    return pm;
}
static int
parse_args(int argc, char **argv)
{
    int opt;
    char **argvopt;
    int option_index;
    char *prgname = argv[0];
    static struct option lgopts[] = {
        {NULL, 0, 0, 0}
    };
    uint64_t port_mask, i, mask;
    argvopt = argv;
    while ((opt = getopt_long(argc, argvopt, "p:", lgopts, &option_index)) != EOF) {
        switch (opt) {
        case 'p':
            port_mask = parse_portmask(optarg);
            if (port_mask == 0) {
                printf("invalid port mask (null port mask)\n");
                print_usage(prgname);
                return -1;
            }
            for (i = 0, mask = 1; i < 64; i ++, mask <<= 1){
                if (mask & port_mask){
                    port_rx = i;
                    port_mask &= ~ mask;
                    break;
                }
            }
            for (i = 0, mask = 1; i < 64; i ++, mask <<= 1){
                if (mask & port_mask){
                    port_tx = i;
                    port_mask &= ~ mask;
                    break;
                }
            }
            if (port_mask != 0) {
                printf("invalid port mask (more than 2 ports)\n");
                print_usage(prgname);
                return -1;
            }
            break;
        default:
            print_usage(prgname);
            return -1;
        }
    }
    if (optind <= 1) {
        print_usage(prgname);
        return -1;
    }
    argv[optind-1] = prgname;
    optind = 1; 
    return 0;
}
int
main(int argc, char **argv)
{
    uint32_t lcore_id;
    uint16_t nb_rxd = NIC_RX_QUEUE_DESC;
    uint16_t nb_txd = NIC_TX_QUEUE_DESC;
    int ret;
    
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Invalid EAL parameters\n");
 
    argc -= ret;
    argv += ret;
        rte_exit(EXIT_FAILURE, 
"This application does not accept more than one core. " 
        "Please adjust the \"-c COREMASK\" parameter accordingly.\n");
    }
    
    ret = parse_args(argc, argv);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Invalid input arguments\n");
 
    
    if (pool == NULL)
        rte_exit(EXIT_FAILURE, 
"Buffer pool creation error\n");
 
    
    conf = port_conf;
    conf.rx_adv_conf.rss_conf.rss_hf &= dev_info.flow_type_rss_offloads;
    if (conf.rx_adv_conf.rss_conf.rss_hf !=
        printf("Port %u modified RSS hash function based on hardware support,"
            "requested:%#"PRIx64" configured:%#"PRIx64"\n",
            port_rx,
            conf.rx_adv_conf.rss_conf.rss_hf);
    }
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d configuration error (%d)\n", port_rx, ret);
 
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d adjust number of descriptors error (%d)\n",
 
                port_rx, ret);
    rxq_conf = dev_info.default_rxconf;
    rxq_conf.offloads = conf.rxmode.offloads;
                &rxq_conf, pool);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d RX queue setup error (%d)\n", port_rx, ret);
 
    txq_conf = dev_info.default_txconf;
    txq_conf.offloads = conf.txmode.offloads;
                &txq_conf);
    if (ret < 0)
    rte_exit(EXIT_FAILURE, 
"Port %d TX queue setup error (%d)\n", port_rx, ret);
 
    conf = port_conf;
    conf.rx_adv_conf.rss_conf.rss_hf &= dev_info.flow_type_rss_offloads;
    if (conf.rx_adv_conf.rss_conf.rss_hf !=
        printf("Port %u modified RSS hash function based on hardware support,"
            "requested:%#"PRIx64" configured:%#"PRIx64"\n",
            port_tx,
            conf.rx_adv_conf.rss_conf.rss_hf);
    }
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d configuration error (%d)\n", port_tx, ret);
 
    nb_rxd = NIC_RX_QUEUE_DESC;
    nb_txd = NIC_TX_QUEUE_DESC;
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d adjust number of descriptors error (%d)\n",
 
                port_tx, ret);
    rxq_conf = dev_info.default_rxconf;
    rxq_conf.offloads = conf.rxmode.offloads;
                NULL, pool);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d RX queue setup error (%d)\n", port_tx, ret);
 
    txq_conf = dev_info.default_txconf;
    txq_conf.offloads = conf.txmode.offloads;
                NULL);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d TX queue setup error (%d)\n", port_tx, ret);
 
    if (tx_buffer == NULL)
        rte_exit(EXIT_FAILURE, 
"Port %d TX buffer allocation error\n",
 
                port_tx);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d start error (%d)\n", port_rx, ret);
 
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Port %d start error (%d)\n", port_tx, ret);
 
    
    ret = app_configure_flow_table();
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Invalid configure flow table\n");
 
    
            return -1;
    }
    return 0;
}