#include <arpa/inet.h>           
#include <signal.h>              
#include <stdint.h>              
#include <stdio.h>               
#include <stdlib.h>              
#include <string.h>              
#include <sys/socket.h>          
#include <unistd.h>              
#include <net/ethernet.h>        
#include <netinet/in.h>          
#include <sched.h>               
#include <stddef.h>              
 
 
 
 
#include "cnet-graph.h"
 
static struct cnet_info cnet_info;
struct cnet_info *cinfo = &cnet_info;
 
typedef int (*cb_types_t)(int cd);
 
#define foreach_thd_lport(_t, _lp) \
    for (int _i = 0; _i < _t->lport_cnt && (_lp = _t->lports[_i]); _i++, _lp = _t->lports[_i])
 
 
static inline int
add_graph_pattern(graph_info_t *gi, const char *pattern)
{
    if ((gi->cnt + 1) > gi->nb_patterns) {
        gi->cnt++;
        gi->patterns = realloc(gi->patterns, ((gi->cnt + 1) * sizeof(char *)));
        if (!gi->patterns)
    }
    gi->patterns[gi->nb_patterns++] = strdup(pattern);
    gi->patterns[gi->nb_patterns]   = NULL;
    return 0;
}
 
static int
initialize_graph(
jcfg_thd_t *thd, graph_info_t *gi)
 
{
    int ret;
 
    snprintf(graph_name, 
sizeof(graph_name), 
"cnet_%d", 
cne_id());
 
 
    if (cinfo->flags & FWD_DEBUG_STATS)
        cne_printf(
"[magenta]Graph Name[]: '[orange]%s[]', [magenta]Thread name [orange]%s[]\n",
 
                   graph_name, thd->name);
    if (ret < 0)
        CNE_ERR_GOTO(err, 
"Unable to find %s option name\n", thd->name);
 
 
        CNE_ERR_GOTO(err, 
"Thread %s does not have any graph patterns\n", thd->name);
 
 
    if (cinfo->flags & FWD_DEBUG_STATS)
    for (
int i = 0; i < pattern_array->
array_sz; i++) {
 
        char *pat = pattern_array->
arr[i]->
str;
 
 
        if ((CNET_ENABLE_TCP == 0) && !strncasecmp("tcp*", pat, 4))
            continue;
        if (cinfo->flags & FWD_DEBUG_STATS)
 
        if (add_graph_pattern(gi, pat))
            goto err;
    }
    if (cinfo->flags & FWD_DEBUG_STATS)
 
    foreach_thd_lport (thd, lport) {
        snprintf(node_name, 
sizeof(node_name), 
"eth_rx-%u", lport->
lpid);
 
        if (add_graph_pattern(gi, node_name))
            goto err;
    }
 
        CNE_ERR_GOTO(err, 
"cne_graph_create(): graph_id '%s' for uid %u\n", graph_name, 
cne_id());
 
 
    if (!gi->graph)
        CNE_ERR_GOTO(err, 
"cne_graph_lookup(): graph '%s' not found\n", graph_name);
 
    this_stk->graph = gi->graph;
 
    free(gi->patterns);
 
    return 0;
err:
    free(gi->patterns);
    return -1;
}
 
#define RECV_NB_MBUFS 128
 
static int
udp_recv(int cd)
{
    ssize_t nb_mbufs;
 
    switch (cinfo->test) {
    case DROP_TEST:
        nb_mbufs = 
chnl_recv(cd, mbufs, RECV_NB_MBUFS);
 
        if (nb_mbufs > 0)
        else if (nb_mbufs < 0)
            CNE_ERR("Receive packets failed\n");
        break;
 
    case LOOPBACK_TEST:
        nb_mbufs = 
chnl_recv(cd, mbufs, RECV_NB_MBUFS);
 
        if (nb_mbufs > 0) {
                CNE_ERR("Unable to send packets\n");
            }
        } else if (nb_mbufs < 0)
            CNE_ERR("Receive packets failed\n");
        break;
 
    case TXONLY_TEST:
        break;
 
    default:
        break;
    }
 
    return 0;
}
 
static int
udp_close(int cd)
{
    CNE_DEBUG("Close channel %d\n", cd);
    return 0;
}
 
static int
tcp_accept(int cd)
{
    int ncd;
    struct sockaddr addr = {0};
    socklen_t addr_len;
 
    addr_len = sizeof(struct sockaddr_in);
    if (ncd < 0)
        CNE_ERR_RET(
"Accept returned an error from %d descriptor\n", cd);
 
    CNE_DEBUG("Accept new chnl %d\n", ncd);
 
    return 0;
}
 
static int
tcp_recv(int cd)
{
    int nb_mbufs;
 
    switch (cinfo->test) {
    case DROP_TEST:
        nb_mbufs = 
chnl_recv(cd, mbufs, RECV_NB_MBUFS);
 
        if (nb_mbufs <= 0) {
            if (nb_mbufs < 0 && errno != ENOTCONN)
                CNE_ERR("Receive packets failed: %d %s\n", errno, strerror(errno));
            break;
        }
 
            for (int i = 0; i < nb_mbufs; i++) {
            }
        }
 
        break;
 
    case LOOPBACK_TEST:
        nb_mbufs = 
chnl_recv(cd, mbufs, RECV_NB_MBUFS);
 
        if (nb_mbufs <= 0) {
            if (nb_mbufs < 0)
                CNE_ERR("Receive packets failed %d: %s\n", errno, strerror(errno));
            break;
        }
 
        CNE_DEBUG("Loopback Received %d\n", nb_mbufs);
            CNE_ERR("Unable to send packets\n");
        }
        break;
 
    case TXONLY_TEST:
        break;
 
    default:
        break;
    }
 
    return 0;
}
 
static int
{
    CNE_DEBUG("Close channel %d\n", cd);
        CNE_ERR_RET(
"unable to close connection on %d channel\n", cd);
 
    return 0;
}
 
static int
proto_callback(int ctype, int cd)
{
        udp_recv, udp_close, tcp_accept, tcp_recv, tcp_close,
    };
 
        return funcs[ctype](cd);
 
    return -1;
}
 
void
thread_func(void *arg)
{
    graph_info_t *gi;
    pthread_t pid = pthread_self();
    int tid;
 
            CNE_RET(
"pthread_setaffinity_np('%s') failed\n", thd->name);
 
    }
 
 
    
    if (pthread_barrier_wait(&cinfo->barrier) > 0)
 
        CNE_RET(
"cnet_stk_initialize('%s') failed\n", thd->name);
 
 
 
    if (tid >= cne_countof(cinfo->graph_info))
        CNE_ERR_GOTO(err, 
"Number of threads cannot be >= %d\n", cne_countof(cinfo->graph_info));
 
    gi = &cinfo->graph_info[tid];
 
    if (initialize_graph(thd, gi))
 
    
    snprintf(chnl_name, sizeof(chnl_name), "%s-chnl", thd->name);
 
        CNE_ERR_GOTO(skip, 
"Unable to find %s option name\n", thd->name);
 
 
        CNE_ERR_GOTO(skip, 
"Thread %s does not have any graph patterns\n", thd->name);
 
 
    if (cinfo->flags & FWD_DEBUG_STATS)
        cne_printf(
"  [magenta]Channels[]: [cyan]%s[]\n%-12s", chnl_name, 
"");
 
    for (
int i = 0; i < chnl_array->
array_sz; i++) {
 
        char *s = chnl_array->arr[i]->
str;
 
 
        if (!s || (s[0] == '\0'))
 
        if (cinfo->flags & FWD_DEBUG_STATS)
                      proto_callback) < 0)
            break;
        if (cinfo->flags & FWD_DEBUG_STATS)
    }
    if (cinfo->flags & FWD_DEBUG_STATS)
 
skip:
 
    return;
err:
    if (pthread_barrier_wait(&cinfo->barrier))
        CNE_ERR("Barrier wait failed: %s\n", strerror(errno));
}
 
void
thread_timer_func(void *arg)
{
 
        pthread_t pid = pthread_self();
 
            CNE_RET(
"pthread_setaffinity_np('%s') failed\n", thd->name);
 
    }
 
 
 
    
    if (pthread_barrier_wait(&cinfo->barrier) > 0)
        CNE_RET(
"Failed to wait for barrier\n");
 
 
 
    CNE_DEBUG(
"Timer assigned to lcore %d, terminating\n", 
cne_lcore_id());
 
}
 
static int
{
 
 
        foreach_thd_lport (thd, lport) {
            cne_printf(
"    [orange]Close[] [magenta]lport [red]%d[] - '[cyan]%s[]'\n", lport->
lpid,
 
                       lport->name);
                CNE_ERR("pktdev_close() returned error\n");
        }
    }
    return 0;
}
 
static void
my_quit(struct cnet_info *ci)
{
    if (ci) {
        jcfg_thread_foreach(ci->jinfo, _thread_quit, ci);
 
    }
}
 
static void
__on_exit(int val, void *arg, int exit_type)
{
    struct cnet_info *ci = arg;
 
    switch (exit_type) {
        switch (val) {
        case SIGUSR1: 
            break;
 
        case SIGINT: 
            cne_printf_pos(99, 1, 
"\n>>> [cyan]Terminating with signal [green]%d[]\n", val);
 
            break;
 
        default:
            cne_printf_pos(99, 1, 
"\n>>> [cyan]Terminating with signal [red]%d[]\n", val);
 
            break;
        }
        break;
 
        cne_printf_pos(99, 1, 
"\n>>> [cyan]Terminating with status [green]%d[]\n", val);
 
        break;
 
        cne_printf_pos(99, 1, 
"\n>>> [cyan]User called exit, with [red]%d[]\n", val);
 
        break;
 
    default:
        cne_printf_pos(99, 1, 
"\n>>> [cyan]Unknow Exit type %d[]\n", exit_type);
 
        break;
    }
    my_quit(ci);
}
 
static int
initialize(void)
{
    uint16_t nb_conf = 0;
 
    CNE_DEBUG(
"pktmbuf_t size %ld, udata64 offset %ld\n", 
sizeof(
pktmbuf_t),
 
 
        pkt_conf[nb_conf++].port_id = lportid;
 
    
 
    return 0;
}
 
static int
cli_tree(void)
{
    
}
 
int
main(int argc, char **argv)
{
    const char *tests[] = {"Unknown", "Drop", "Loopback", "Tx Only", NULL};
    int signals[]       = {SIGINT, SIGTERM, SIGUSR1};
 
    memset(&cnet_info, 0, sizeof(struct cnet_info));
 
    if (
cne_init() < 0 || parse_args(argc, argv))
 
 
    if (
cne_on_exit(__on_exit, cinfo, signals, cne_countof(signals)) < 0)
 
 
    cne_printf(
"\n[yellow]*** [cyan:-:italic]CNET-GRAPH Application[], " 
               "[green]Mode[]: [magenta:-:italic]%s[], "
               "[green]Burst Size[]: [magenta]%d[] \n",
               tests[cinfo->test], cinfo->burst);
    cne_printf(
"\n*** [yellow]cnet-graph[], [blue]PID[]: [green]%d[] [blue]lcore[]: [green]%d[]\n",
 
 
    
    if (!cinfo->cnet)
 
    usleep(1000);
 
    if (initialize())
 
 
    
 
    
    if (pthread_barrier_wait(&cinfo->barrier) > 0)
 
    if (pthread_barrier_destroy(&cinfo->barrier))
    usleep(500000);
 
    
 
    cne_printf(
">>> [cyan]CNET-Graph Application Exiting[]: [green]Bye![]\n");
 
    return 0;
 
err:
    if (pthread_barrier_destroy(&cinfo->barrier))
        CNE_ERR("Failed to destroy barrier\n");
leave:
    cne_printf(
"\n*** [cyan]cnet-graph Application[], [blue]PID[]: [green]%d[] failed\n", getpid());
 
    return -1;
}
CNDP_API void cli_start(const char *msg)
 
CNDP_API int cli_setup_with_tree(cli_tree_t tree)
 
CNDP_API void cli_destroy(void)
 
CNDP_API int cli_create(struct cli_cfg *cfg)
 
CNDP_API int cli_create_with_defaults(struct cli_cfg *cfg)
 
CNDP_API int cne_id(void)
 
CNDP_API int cne_init(void)
 
CNDP_API int cne_on_exit(on_exit_fn_t exit_fn, void *arg, int *signals, int nb_signals)
 
#define offsetof(TYPE, MEMBER)
 
CNDP_API int cne_graph_destroy(cne_graph_t id)
 
CNDP_API cne_graph_t cne_graph_create(const char *name, const char **patterns)
 
CNDP_API struct cne_graph * cne_graph_lookup(const char *name)
 
#define CNE_GRAPH_ID_INVALID
 
#define CNE_GRAPH_NAMESIZE
 
static void cne_graph_walk(struct cne_graph *graph)
 
CNDP_API uint32_t cne_log_get_level(void)
 
#define CNE_ERR_GOTO(lbl,...)
 
CNDP_API int cne_printf_pos(int16_t r, int16_t c, const char *fmt,...)
 
CNDP_API int cne_printf(const char *fmt,...)
 
CNDP_API int cne_lcore_id(void)
 
void cne_timer_subsystem_init(void)
 
void cne_timer_manage(void)
 
CNDP_API struct cnet * cnet_create(void)
Create cnet structure and use default value, will call cnet_config_create().
 
CNDP_API int cnet_add_cli_cmds(void)
Called to initialize the CLI commands for the CNET structure.
 
CNDP_API void cnet_stop(void)
Stop and free resources of the cnet structure.
 
CNDP_API int chnl_open(const char *str, int flags, chnl_cb_t fn)
 
CNDP_API int chnl_recv(int cd, pktmbuf_t **mbufs, size_t len)
 
#define CHNL_ENABLE_UDP_CHECKSUM
 
CNDP_API int chnl_accept(int cd, struct sockaddr *sa, socklen_t *addrlen)
Accept on a channel similar to 'accept()'.
 
CNDP_API int chnl_send(int cd, pktmbuf_t **mbufs, uint16_t nb_mbufs)
 
CNDP_API int chnl_close(int cd)
 
CNDP_API int cnet_stk_initialize(struct cnet *cnet)
Initialize the stack instance.
 
CNDP_API int cnet_eth_node_config(struct pkt_eth_node_config *cfg, uint16_t cnt)
 
CNDP_API int jcfg_option_array_get(jcfg_info_t *jinfo, const char *name, obj_value_t **val_arr)
 
CNDP_API int metrics_destroy(void)
 
CNDP_API int pktdev_close(uint16_t lport_id)
 
CNDP_API uint16_t pktdev_port_count(void)
 
#define pktmbuf_data_len(m)
 
#define pktmbuf_mtod(m, t)
 
static void pktmbuf_free_bulk(pktmbuf_t **mbufs, unsigned int count)