/*
 * Copyright (c) 2002-2005 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: dagstats.c 4330 2006-05-08 04:45:34Z trisha $
 */

/* Endace headers. */
#include "dag_config_api.h"
#include "dagclarg.h"
#include "dagapi.h"
#include "dag_platform.h"


#define BUFFER_SIZE 256
#define SAFETY_COUNT 0xfffff

/* CVS Header. */
static const char* const kCvsHeader __attribute__ ((unused)) = "$Id: dagstats.c 4330 2006-05-08 04:45:34Z trisha $";
static const char* const kRevisionString = "$Revision: 4330 $";

static bool find_module_name(const char* suspect);
static void print_status(dag_card_ref_t card, dag_component_t sac);
static void display_counter_header();
static void display_counters();
static void enable_disable_modules(dag_card_ref_t card, dag_component_t sac, const char* enable_options, bool enable);
static void drain_erfs(dag_card_ref_t card, dag_component_t sac, const char* drain_options);
static void reset_module(dag_card_ref_t card, dag_component_t sac);
char * device_name = "/dev/dag0"; /*Device name */
uint8_t tcp_flow_counter = 0;
uint8_t ip_counter = 0;
uint8_t interval = 0;

static int dagstream = 0;
static char dagname[BUFFER_SIZE];
static char dagname_buf[BUFFER_SIZE] = "dag0";
char module_names[4][BUFFER_SIZE] = {"all", "global", "tcp", "ip"};

/* Commandline argument codes. */
enum
{
    CLA_DEVICE,
    CLA_HELP,
    CLA_TCP_FLOW_COUNTER,
    CLA_IP_COUNTER,
    CLA_REPEAT_INTERVAL,
    CLA_DRAIN,
    CLA_VERBOSE,
    CLA_ENABLE,
    CLA_DISABLE,
    CLA_RESET,
    CLA_DP_RESET,
    CLA_CLEAR,
    CLA_STATUS,
    CLA_VERSION
};

typedef struct options
{
    bool enable;
    bool disable;
    bool drain;
    bool dp_reset;
    bool clear;
    bool status;
} options_t;

static void
print_version(void)
{
	printf("dagstats (DAG %s) %s\n", kDagReleaseVersion, kRevisionString);
}


int
dagstats_main(int argc, char* argv[])
{
    dag_card_ref_t card_ref = NULL;
    dag_component_t root_component = NULL;
    dag_component_t sac = NULL;
    ClArgPtr clarg = NULL;
    int result = 0;
    int reset = 0;
    int argindex = 0;
    int code = 0;
    char output_filename[BUFFER_SIZE];
    char enable_options[BUFFER_SIZE];
    char disable_options[BUFFER_SIZE];
    char drain_options[BUFFER_SIZE];
	dag_reg_t reg_result[DAG_REG_MAX_ENTRIES];
    uint32_t idt_base;
    volatile uint8_t* dagiom = NULL;
    int v_level = 0;
    options_t options;
                    
    memset(output_filename, 0, BUFFER_SIZE);
    memset(&options, 0, sizeof(options_t));
    memset(enable_options, 0, BUFFER_SIZE);
    memset(disable_options, 0, BUFFER_SIZE);
    memset(drain_options, 0, BUFFER_SIZE);

	/* Set up default DAG device. */
	clarg = dagclarg_init(argc, (const char** const)argv);
	if (-1 == dag_parse_name(dagname_buf, dagname, BUFFER_SIZE, &dagstream))
	{
        dagutil_panic("dag_parse_name(%s): %s\n", dagname_buf, strerror(errno));
	}
    dagclarg_add_string(clarg, "DAG device to use.", "--device", 'd', "device", dagname_buf, DAGNAME_BUFSIZE, CLA_DEVICE);
	dagclarg_add(clarg, "This page.", "--help", 'h', CLA_HELP);
    dagclarg_add(clarg, "Print IP Counter value", "--ip_counter", 'a', CLA_IP_COUNTER);
    dagclarg_add(clarg, "Print TCP Flow Counter value", "--tcp_flow_counter", 't', CLA_TCP_FLOW_COUNTER);
    dagclarg_add(clarg, "Repeat interval", "--interval", 'i', CLA_REPEAT_INTERVAL);
    dagclarg_add(clarg, "Datapath reset", "--datapath", 'p', CLA_DP_RESET);
	dagclarg_add(clarg, "Display version information.", "--version", 'V', CLA_VERSION);
    dagclarg_add(clarg, "Clear", "--clear", 'c', CLA_CLEAR);
    dagclarg_add(clarg, "Status", "--status", 's', CLA_STATUS);
	dagclarg_add_int(clarg, "Verbosity", "--verbosity", 'v', "level", &v_level, CLA_VERBOSE);
    dagclarg_add_string(clarg, "Drain erfs to memory hole. Available options are: all tcp ip\n"
            "\t\t\t\t\tUsage example: dagstats --drain \"ip\"", "--drain", 'D', "options", drain_options, BUFFER_SIZE, CLA_DRAIN);
    dagclarg_add(clarg, "Reset the stats module", "--reset", 'r', CLA_RESET);
    dagclarg_add_string(clarg, "Enable the modules or all of them. Available options are: all global ip tcp.\n"
            "\t\t\t\t\tUsage example: dagstats -e \"global\" ", "--enable", 'e', "options", enable_options, BUFFER_SIZE, CLA_ENABLE);
    dagclarg_add_string(clarg, "Disable the modules or all of them. Available options are: all global ip tcp.\n"
            "\t\t\t\t\tUsage example: dagstats -x \"global \" ", "--disable", 'x', "options", disable_options, BUFFER_SIZE, CLA_DISABLE);
    if(argc == 1)
    {
        dagclarg_display_usage(clarg, stdout);
        return EXIT_FAILURE;
    }

    dagutil_set_progname("dagstats");
    /* Parse the command line options. */
	result = dagclarg_parse(clarg, NULL, &argindex, &code);
    while (1 == result)
    {
        switch (code)
        {
            case CLA_DEVICE:
                if (-1 == dag_parse_name(dagname_buf, dagname, DAGNAME_BUFSIZE, &dagstream))
                {
                    dagutil_panic("dag_parse_name(%s): %s\n", dagname_buf, strerror(errno));
                }
                break;

            case CLA_HELP:
                dagclarg_display_usage(clarg, stdout);
                return EXIT_SUCCESS;

            case CLA_IP_COUNTER:
                ip_counter = 1;
                break;

            case CLA_TCP_FLOW_COUNTER:
                tcp_flow_counter = 1;
                break;

            case CLA_REPEAT_INTERVAL:
                if(interval == 0)
                {
                    interval = 1;
                }
                break;

            case CLA_RESET:
                reset = 1;
                break;

            case CLA_DRAIN:
                options.drain = true;
                break;
            
            case CLA_ENABLE:
                options.enable = true;
                break;

            case CLA_DISABLE:
                options.disable = true;
                break;

            case CLA_DP_RESET:
                options.dp_reset = true;
                break;

            case CLA_CLEAR:
                options.clear = true;
                break;

            case CLA_STATUS:
                options.status = true;
                break;
                
            case CLA_VERSION:
                print_version();
                return EXIT_SUCCESS;

        }
        result = dagclarg_parse(clarg, NULL, &argindex, &code);
    }
    dagutil_set_verbosity(v_level);

    card_ref = dag_config_init(dagname);
    if (card_ref == NULL)
    {
        dagutil_panic("No card\n");
    }

    dagiom = dag_iom(dag_config_get_card_fd(card_ref));
	if ((dag_reg_find((char*)dagiom, DAG_REG_IDT_TCAM, reg_result)) == 0)
    {
        dagutil_panic("No IDT copro\n");
    }
    else
    {
		idt_base = DAG_REG_ADDR(*reg_result);
    }
    
    root_component = dag_config_get_root_component(card_ref);
    sac = dag_component_get_subcomponent(root_component, kComponentSingleAttributeCounter, 0);

    if(sac == kComponentInvalid)
    {
        /* No component exists */
        dagutil_panic("Single Attribute Counter Module does not exist on card\n");
    }

    if (reset == 1)
    {
        attr_uuid_t init_attr;
        attr_uuid_t search_attr;
        dag_component_t sc256;
        sc256_search_length_t sl = kSC256SearchLength72;

        sc256 = dag_component_get_subcomponent(root_component, kComponentSC256, 0);
        if (!sc256)
            dagutil_panic("Failed to get the SC256 component\n");
        enable_disable_modules(card_ref, sac, "all", false);
        *(volatile uint32_t*)(dagiom + 0x20dc) = 0x20000000;
        init_attr = dag_component_get_attribute_uuid(sc256, kNullAttributeSC256Init);
        dag_config_set_null_attribute(card_ref, init_attr);
        search_attr = dag_component_get_attribute_uuid(sc256, kUint32AttributeSC256SearchLength);
        dag_config_set_uint32_attribute(card_ref, search_attr, sl);
        *(volatile uint32_t*)(dagiom + 0x20dc) = 0x40000000;
        reset_module(card_ref, sac);
    }

    if (options.dp_reset)
    {
        /* do a datapath reset */
        *(volatile uint32_t*)(dagiom + 0x88) = 0x80000000;
    }
    if (options.enable)
    {
        enable_disable_modules(card_ref, sac, enable_options, true);
    }

    if (options.disable)
    {
        enable_disable_modules(card_ref, sac, disable_options, false);
    }

    if (options.clear)
    {
        reset_module(card_ref, sac);
    }

    if (options.status)
    {
        print_status(card_ref, sac);
    }

    if (options.drain)
    {
        /* do a datapath reset*/
    /*  *(volatile uint32_t*)(dagiom + 0x88) = 0x80000000;
        *(volatile uint32_t*)(dagiom + 0x20dc) = 0x40000000;*/
        drain_erfs(card_ref, sac, drain_options);
    }
    else if (tcp_flow_counter || ip_counter)
    {
        /* Display Statistics */
        if(interval == 0)
        {
            display_counter_header();
            printf("\n");
            display_counters(card_ref, sac);
            printf("\n");
        }
        else
        {
            int count = 0;
            display_counter_header();
            printf("\n");
            while(true)
            {
                display_counters(card_ref, sac);
                printf("\n");
                count++;
                if(count >=20)
                {
                    count = 0;
                    display_counter_header();
                    printf("\n");
                }
                sleep(interval);
            }
        }
    }
    return  EXIT_SUCCESS;
}

static void
print_status(dag_card_ref_t card, dag_component_t sac)
{
    attr_uuid_t attr = 0;
    bool val = 0;

    dagutil_verbose_level(1, "Printing Status");

    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
    val = dag_config_get_boolean_attribute(card, attr);
    printf("Global Enable: %s\n", val ? "enabled":"disabled");
    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableIPAddressCounter);
    val = dag_config_get_boolean_attribute(card, attr);
    printf("IP Counter : %s\n", val ? "enabled":"disabled");
    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableTCPFlowCounter);
    val = dag_config_get_boolean_attribute(card, attr);
    printf("TCP Flow Counter: %s\n", val ? "enabled":"disabled");
}

static void
drain_erfs(dag_card_ref_t card, dag_component_t sac, const char* drain_options)
{
    attr_uuid_t attr = 0;
    attr_uuid_t global = 0;
    int safety = SAFETY_COUNT;
    char* start = NULL;
    char* p = NULL;
    char suspect[BUFFER_SIZE];

    /* Check for bad options */
    start = (char*)drain_options;
    p = strstr(start, " ");
    memset(suspect, 0, BUFFER_SIZE);
    do
    {
        if (p != NULL)
        {
            memcpy(suspect, start, p - start);
            suspect[p - start] = 0;
            p++;
            start = p;
            p = strstr(start, " ");
            if (!find_module_name(suspect))
            {
                dagutil_warning("Unrecognized option %s\n", suspect);
            }
        }
    } while (p != NULL);
    strcpy(suspect, start);
    if (!find_module_name(suspect))
    {
        dagutil_warning("Unrecognized option %s\n", suspect);
    }

    dagutil_verbose_level(1, "Draining data from Copro - make sure dagsnap is running.\n");
    global = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);

    if (strstr(drain_options, "all") != NULL)
    {

        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableIPAddressCounter);
        if (dag_config_get_boolean_attribute(card, global) == 1 && dag_config_get_boolean_attribute(card, attr) == 1)
            dagutil_panic("Disable the IP Counter module before trying to drain it\n");

        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableTCPFlowCounter);
        if (dag_config_get_boolean_attribute(card, global) == 1 && dag_config_get_boolean_attribute(card, attr) == 1)
            dagutil_panic("Disable the TCP Counter module before trying to drain it\n");

        safety = SAFETY_COUNT;
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableTCPFlowModule);
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the TCP flow enable bit...\n");
            safety--;
        }

        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for TCP flow ready bit!\n");
        }


        /* Drain the tcp flow counter records */
        dagutil_verbose_level(2, "Writing drain bit to tcp flow counter module\n");
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeGenerateTCPFlowCounterErf);
        dag_config_set_boolean_attribute(card, attr, 1);

        safety = SAFETY_COUNT;
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableTCPFlowModule);
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the TCP flow enable bit...\n");
            safety--;
        }

        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for TCP Flow ready bit!\n");
        }

        safety = SAFETY_COUNT;
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the IP Counter enable bit...\n");
            safety--;
        }

        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for IP Counter ready bit!\n");
        }


        /* Drain the ip counter erf records*/
        dagutil_verbose_level(2, "Writing drain bit to ip counter module\n");
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeGenerateIPCounterErf);
        dag_config_set_boolean_attribute(card, attr, 1);
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableIPCounterModule);
        safety = SAFETY_COUNT;
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the IP Counter enable bit...\n");
            safety--;
        }
        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for IP Counter ready bit!\n");
        }

    }
    else if (strstr(drain_options, "tcp") != NULL)
    {
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableTCPFlowCounter);
        if (dag_config_get_boolean_attribute(card, global) == 1 && dag_config_get_boolean_attribute(card, attr) == 1)
            dagutil_panic("Disable the TCP Counter module before trying to drain it\n");

        safety = SAFETY_COUNT;
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableTCPFlowModule);
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the TCP flow enable bit...\n");
            safety--;
        }
        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for TCP flow ready bit!\n");
        }


        /* Drain the tcp flow counter records */
        dagutil_verbose_level(2, "Writing drain bit to tcp flow counter module\n");
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeGenerateTCPFlowCounterErf);
        dag_config_set_boolean_attribute(card, attr, 1);

        safety = SAFETY_COUNT;
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableTCPFlowModule);
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the TCP flow enable bit...\n");
            safety--;
        }

        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for TCP flow ready bit!\n");
        }

    }
    else if (strstr(drain_options, "ip") != NULL)
    {
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableIPAddressCounter);
        if (dag_config_get_boolean_attribute(card, global) == 1 && dag_config_get_boolean_attribute(card, attr) == 1)
            dagutil_panic("Disable the IP Counter module before trying to drain it\n");

        safety = SAFETY_COUNT;
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableIPCounterModule);
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the IP Counter enable bit...\n");
            safety--;
        }
        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for IP Counter ready bit!\n");
        }

        /* Drain the ip counter erf records*/
        dagutil_verbose_level(2, "Writing drain bit to ip counter module\n");
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeGenerateIPCounterErf);
        dag_config_set_boolean_attribute(card, attr, 1);

        safety = SAFETY_COUNT;
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableIPCounterModule);
        while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
        {
            dagutil_verbose_level(4, "Waiting for the IP Counter enable bit...\n");
            safety--;
        }
        if (safety <= 0)
        {
            dagutil_verbose_level(0, "Timed out while waiting for IP Counter ready bit!\n");
        }
    }
}

static void
reset_module(dag_card_ref_t card, dag_component_t sac)
{

#if 0
    volatile uint8_t* dagiom = 0;

    dagiom = dag_iom(dag_config_get_card_fd(card));
    *(volatile uint32_t*)(dagiom + 0x2100) = 0x200;
    *(volatile uint32_t*)(dagiom + 0x2104) = 0x1;
    *(volatile uint32_t*)(dagiom + 0x2108) = 0x1;
#endif
    
    attr_uuid_t attr = 0;

    /* disable modules before reset */
    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
    dag_config_set_boolean_attribute(card, attr, 0);
    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableIPAddressCounter);
    dag_config_set_boolean_attribute(card, attr, 0);
    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableTCPFlowCounter);
    dag_config_set_boolean_attribute(card, attr, 0);

    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeTCAMInit);
    dag_config_set_boolean_attribute(card, attr, 1);

    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeResetTCPFlowCounter);
    dag_config_set_boolean_attribute(card, attr, 1);
    attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeResetIPCounter);
    dag_config_set_boolean_attribute(card, attr, 1);

}

static void 
display_counter_header()
{
    if(tcp_flow_counter == 1)
    {
        printf("TCP Flows  ");
    }
    if(ip_counter == 1)
    {
        printf("IP Addresses");
    }
}

static void
display_counters(dag_card_ref_t card, dag_component_t sac)
{
    attr_uuid_t any_uuid;
    if(tcp_flow_counter == 1)
    {
        /* Read tcp flow counter */
        any_uuid = dag_component_get_attribute_uuid(sac, kUint32AttributeTcpFlowCounter);
        assert(any_uuid != kNullAttributeUuid);
        printf("%9u", dag_config_get_uint32_attribute(card, any_uuid));
    }
    if(ip_counter == 1)
    {
        /* Read ip counter */
        any_uuid = dag_component_get_attribute_uuid(sac, kUint32AttributeIpAddressCounter);
        assert(any_uuid != kNullAttributeUuid);
        printf("%14u", dag_config_get_uint32_attribute(card, any_uuid));
    }
}

static bool
find_module_name(const char* suspect)
{
    bool found = false;
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        if (strcmp(suspect, module_names[i]) == 0)
        {
            found = true;
            break;
        }
    }
    return found;
}

static void
enable_disable_modules(dag_card_ref_t card, dag_component_t sac, const char* enable_options, bool enable)
{
    attr_uuid_t attr = 0;
    int safety = SAFETY_COUNT;
    char* p = NULL;
    char* start = NULL;
    char suspect[BUFFER_SIZE];

    dagutil_verbose_level(1, "%s the following modules: %s\n", enable ? "Enabling":"Disabling", enable_options);
    /* Check for bad options */
    start = (char*)enable_options;
    p = strstr(start, " ");
    memset(suspect, 0, BUFFER_SIZE);
    do
    {
        if (p != NULL)
        {
            memcpy(suspect, start, p - start);
            suspect[p - start] = 0;
            p++;
            start = p;
            p = strstr(start, " ");
            if (!find_module_name(suspect))
            {
                dagutil_warning("Unrecognized option %s\n", suspect);
            }
        }
    } while (p != NULL);
    strcpy(suspect, start);
    if (!find_module_name(suspect))
    {
        dagutil_warning("Unrecognized option %s\n", suspect);
    }

    if (strstr(enable_options, "all") != NULL)
    {
        /* do the global enable first otherwise ready bits on the other modules will not work */
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
        dag_config_set_boolean_attribute(card, attr, enable);

        if (enable)
        {
            safety = SAFETY_COUNT;
            attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableTCPFlowModule);
            while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
            {
                dagutil_verbose_level(4, "Waiting for the TCP flow enable bit...\n");
                safety--;
            }
            if (safety <= 0)
            {
                dagutil_verbose_level(0, "Timed out while waiting for TCP flow ready bit!\n");
            }
        }
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableTCPFlowCounter);
        dag_config_set_boolean_attribute(card, attr, enable);

        if (enable)
        {
            safety = SAFETY_COUNT;
            attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableIPCounterModule);
            while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
            {
                dagutil_verbose_level(4, "Waiting for the IP Counter enable bit...\n");
                safety--;
            }
            if (safety <= 0)
            {
                dagutil_verbose_level(0, "Timed out while waiting for IP Counter ready bit!\n");
            }
        }
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableIPAddressCounter);
        dag_config_set_boolean_attribute(card, attr, enable);
    }
    
    if (strstr(enable_options, "global") != NULL)
    {
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
        dag_config_set_boolean_attribute(card, attr, enable);
    }

    if (strstr(enable_options, "tcp") != NULL)
    {
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
        dag_config_set_boolean_attribute(card, attr, 1);

        if (enable)
        {
            safety = SAFETY_COUNT;
            attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableTCPFlowModule);
            while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
            {
                dagutil_verbose_level(4, "Waiting for the TCP flow enable bit...\n");
                safety--;
            }
            if (safety <= 0)
            {
                dagutil_verbose_level(0, "Timed out while waiting for TCP flow ready bit!\n");
            }
        }

        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableTCPFlowCounter);
        dag_config_set_boolean_attribute(card, attr, enable);

        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
        dag_config_set_boolean_attribute(card, attr, 1);
    }

    if (strstr(enable_options, "ip") != NULL)
    {
        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
        dag_config_set_boolean_attribute(card, attr, 1);

        if (enable)
        {
            safety = SAFETY_COUNT;
            attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeReadyEnableIPCounterModule);
            while (dag_config_get_boolean_attribute(card, attr) == false && safety > 0)
            {
                dagutil_verbose_level(4, "Waiting for the IP Counter enable bit...\n");
                safety--;
            }
            if (safety <= 0)
            {
                dagutil_verbose_level(0, "Timed out while waiting for IP Counter ready bit!\n");
            }
        }

        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableIPAddressCounter);
        dag_config_set_boolean_attribute(card, attr, enable);

        attr = dag_component_get_attribute_uuid(sac, kBooleanAttributeEnableCounterModules);
        dag_config_set_boolean_attribute(card, attr, 1);
    }

}

#ifndef ENDACE_UNIT_TEST
int
main(int argc, const char* const * argv)
{
	return dagstats_main(argc, (char**) argv);
}
#endif /* ENDACE_UNIT_TEST */



