/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos72Q src/bos/usr/ccs/lib/libperfstat/simple_seachildren.c 1.4        */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2018              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

static char *sccsid = "@(#)68 1.4     src/bos/usr/ccs/lib/libperfstat/simple_seachildren.c, libperfstat, bos72Q, q2018_45A1 10/27/18 11:12:33 ";

/* The sample program display the metrics *
 * related to each and every Individual   * 
 * physical and virtual/trunk adapters which are under SEA in the VIOS  */

#include <stdio.h> 
#include <stdlib.h>
#include <libperfstat.h>
#include <net/if_types.h>

/* define default interval and count values */
#define INTERVAL_DEFAULT 1
#define COUNT_DEFAULT    1

/* Check value returned by malloc for NULL */

#define CHECK_FOR_MALLOC_NULL(X) {  if ((X) == NULL) {\
                                       perror ("malloc");\
                                       exit(2);\
                                     }\
                  }

int count = COUNT_DEFAULT, interval = INTERVAL_DEFAULT, tot;
int returncode;

/* support for remote node statistics collection in a cluster environment */
perfstat_id_node_t nodeid;
static char nodename[MAXHOSTNAMELEN] = "";
static int collect_remote_node_stats = 0;

/* store the data structures */

static perfstat_netadapter_t *statp ,*statq;

/*
 * NAME: showusage
 *       to display the usage
 *
 */

void showusage(char *cmd)
{
    fprintf (stderr, "usage: %s [-i <interval in seconds> ] [-c <number of iterations> ] [-n <node name in the cluster> ]\n", cmd);
    exit(1);
}


/*
 * NAME: do_initialization
 *       This function initializes the data structues.
 *       It also collects initial set of values.
 *
 * RETURNS:
 * On successful completion:
 *   - returns 0.
 * In case of error
 *    - exits with code 1.
 */

int do_initialization(void)
{
    perfstat_id_t first;

    /* check how many perfstat_netadapter_t structures are available */
    if(collect_remote_node_stats) {
        strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
        /* SEA Adapter Name must be filled */
        strcpy(nodeid.name , FIRST_SEA); 
        /*nodeid.spec = NODENAME; */
        tot = perfstat_bridgedadapters_node(&nodeid, NULL, sizeof(perfstat_netadapter_t), 0);
    } else {
        /* SEA Adapter Name must be filled */
        strcpy(first.name , FIRST_SEA);   
        tot = perfstat_bridgedadapters(&first, NULL, sizeof(perfstat_netadapter_t), 0);
    }
    if (tot == 0) {
        printf("There are no SEA Children\n");
        exit(0);
    }
    if (tot < 0) {
	if (collect_remote_node_stats)
	        perror("perfstat_bridgedadapters_node: ");
	else
	        perror("perfstat_bridgedadapters: ");
		
        exit(1);
    }

    /* allocate enough memory for all the structures */

    statp = (perfstat_netadapter_t *)malloc(tot * sizeof(perfstat_netadapter_t));
    CHECK_FOR_MALLOC_NULL(statp);

    statq = (perfstat_netadapter_t *)malloc(tot * sizeof(perfstat_netadapter_t));
    CHECK_FOR_MALLOC_NULL(statq);


    return(0);
}

/*
 *Name: display_metrics
 *       collect the metrics and display them
 *
 */
void display_metrics()
{
    perfstat_id_t first;
    int ret, i;
    
    if(collect_remote_node_stats) {
        strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
        nodeid.spec = NODENAME;

        /* Valid SEA Adapter Name Must be passed */
        strcpy(nodeid.name , FIRST_SEA);
        ret = perfstat_bridgedadapters_node(&nodeid, statq, sizeof(perfstat_netadapter_t), tot);
    } else {
        /* Valid SEA Adapter Name Must be passed */
        strcpy(first.name , FIRST_SEA);
        ret = perfstat_bridgedadapters( &first, statq, sizeof(perfstat_netadapter_t), tot);
    }
    if (ret < 0) {
        free(statp);
        free(statq);
	if (collect_remote_node_stats)
		perror("perfstat_bridgedadapters_node: ");
	else
		perror("perfstat_bridgedadapters: ");
        exit(1);
    }

    while (count)
    {
        sleep (interval);

        if(collect_remote_node_stats) {
           ret = perfstat_bridgedadapters_node(&nodeid, statp, sizeof(perfstat_netadapter_t), tot);
        } else {
           ret = perfstat_bridgedadapters(&first, statp, sizeof(perfstat_netadapter_t), tot);
        }
       /* print statistics for each of the interfaces */
        for (i = 0; i < ret; i++) {
            printf(" Adapter name: %s \n",  statp[i].name);
            printf(" ======================== Transmit Statistics ============================\n");
            printf(" Transmit Packets: %lld \n", statp[i].tx_packets - statq[i].tx_packets);
            printf(" Transmit Bytes: %lld \n",  statp[i].tx_bytes - statq[i].tx_bytes);
            printf(" Transfer Interrupts : %lld \n",  statp[i].tx_interrupts - statq[i].tx_interrupts);
            printf(" Transmit Errors : %lld \n",  statp[i].tx_errors - statq[i].tx_errors);
            printf(" Packets Dropped at the time of Data Transmission : %lld \n",  statp[i].tx_packets_dropped - statq[i].tx_packets_dropped);
            printf(" Transmit Queue Size: %lld \n",  statp[i].tx_queue_size - statq[i].tx_queue_size);
            printf(" Transmit Queue Length :%lld \n", statp[i].tx_queue_len - statq[i].tx_queue_len);
            printf(" Transmit Queue Overflow : %lld \n", statp[i].tx_queue_overflow - statq[i].tx_queue_overflow);
            printf(" Broadcast Packets Transmitted: %lld \n", statp[i].tx_broadcast_packets - statq[i].tx_broadcast_packets);
            printf(" Multicast packets Transmitted: %lld \n", statp[i].tx_multicast_packets - statq[i].tx_multicast_packets);
            printf(" Lost Carrier Sense signal count : %lld \n",statp[i].tx_carrier_sense - statq[i].tx_carrier_sense);
            printf(" Count of DMA Under-runs for Transmission: %lld \n",statp[i].tx_DMA_underrun - statq[i].tx_DMA_underrun);
            printf(" Number of unsuccessful transmissions : %lld \n",statp[i].tx_lost_CTS_errors - statq[i].tx_lost_CTS_errors);
            printf(" Maximum Collision Errors at Transmission: %lld \n",statp[i].tx_max_collision_errors - statq[i].tx_max_collision_errors);
            printf(" Late Collision Errors at Transmission : %lld \n",statp[i].tx_late_collision_errors - statq[i].tx_late_collision_errors);
            printf(" Number of packets deferred for Transmission : %lld \n",statp[i].tx_deferred - statq[i].tx_deferred);
            printf(" Time Out Errors for Transmission : %lld \n",statp[i].tx_timeout_errors - statq[i].tx_timeout_errors);
            printf(" Count of Single Collision error at Transmission: %lld \n",statp[i].tx_single_collision_count - statq[i].tx_single_collision_count);
            printf(" Count of Multiple Collision error at Transmission : %lld \n",statp[i].tx_multiple_collision_count - statq[i].tx_multiple_collision_count);

            printf(" ========================== Receive Statistics ==============================\n");
            printf(" Receive Packets :%lld \n",statp[i].rx_packets - statq[i].rx_packets);
            printf(" Receive Bytes :%lld \n", statp[i].rx_bytes - statq[i].rx_bytes);
            printf(" Receive Interrupts : %lld \n", statp[i].rx_interrupts - statq[i].rx_interrupts);
            printf(" Input errors on interface :%lld \n", statp[i].rx_errors - statq[i].rx_errors);
            printf(" Nunber of Packets Dropped : %lld \n", statp[i].rx_packets_dropped - statq[i].rx_packets_dropped);
            printf(" Count of Bad Packets Received : %lld \n", statp[i].rx_bad_packets - statq[i].rx_bad_packets);
            printf(" Number of MultiCast Packets Received : %lld \n", statp[i].rx_multicast_packets - statq[i].rx_multicast_packets);
            printf(" Number of Broadcast Packets Received : %lld \n",statp[i].rx_broadcast_packets - statq[i].rx_broadcast_packets);
            printf(" Count of Packets Received with CRC errors: %lld \n",statp[i].rx_CRC_errors - statq[i].rx_CRC_errors);
            printf(" DMA over-runs : %lld \n", statp[i].rx_DMA_overrun - statq[i].rx_DMA_overrun);
            printf(" Alignment Errors : %lld \n", statp[i].rx_alignment_errors - statq[i].rx_alignment_errors);
            printf(" No Resource Errors : %lld \n", statp[i].rx_noresource_errors - statq[i].rx_noresource_errors);
            printf(" Collision Errors: %lld \n",  statp[i].rx_collision_errors - statq[i].rx_collision_errors);
            printf(" Number of Short Packets Received: %lld \n",statp[i].rx_packet_tooshort_errors - statq[i].rx_packet_tooshort_errors);
            printf(" Number of Too Long Packets Received : %lld \n", statp[i].rx_packet_toolong_errors - statq[i].rx_packet_toolong_errors);
            printf(" Number of Received Packets discarded by Adapter: %lld \n", statp[i].rx_packets_discardedbyadapter - statq[i].rx_packets_discardedbyadapter);
            printf(" Adapter Type :%d \n",statp[i].adapter_type);
            printf(" =============================================================================\n");

        }

        memcpy(statq, statp, (tot * sizeof(perfstat_netadapter_t)));
        count--;
    }
}

/*
 *Name: main
 *
 */

int main(int argc, char *argv[])
{
    int i, rc;
    /* get the interval and count values */

    /* Process the arguments */
    while ((i = getopt(argc, argv, "i:c:n:")) != EOF)
    {
        switch(i)
        {
           case 'i':               /* Interval */
                    interval = atoi(optarg);
                    if( interval <= 0 )
                        interval = INTERVAL_DEFAULT;
                    break;
           case 'c':               /* Number of interations */
                    count = atoi(optarg);
                    if( count <= 0 )
                        count = COUNT_DEFAULT;
                    break;
           case 'n':               /* Node name in a cluster environment */
                    strncpy(nodename, optarg, MAXHOSTNAMELEN);
                    nodename[MAXHOSTNAMELEN-1] = '\0';
                    collect_remote_node_stats = 1;
                    break;
           default:
                   /* Invalid arguments. Print the usage and terminate */
                   showusage(argv[0]);
        }
    }

    if(collect_remote_node_stats)
    {   /* perfstat_config needs to be called to enable cluster statistics collection */
        rc = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
        if (rc == -1)
        {
            perror("cluster statistics collection is not available");
            exit(-1);
        }
    }

    do_initialization();
    display_metrics();

    if(collect_remote_node_stats)
    {   /* Now disable cluster statistics by calling perfstat_config */
        perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
    }

    free(statp);
    free(statq);
    return 0;
}

