/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/ccs/lib/libperfstat/simpleprotocolstat.c 1.3.1.2    */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2008,2010              */
/* 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[] = "@(#)75        1.3.1.2  src/bos/usr/ccs/lib/libperfstat/simpleprotocolstat.c, libperfstat, bos720 7/21/10 04:58:41";

/* The sample Program used to retrieve the        *
 * all available protocol statistics in the LPAR  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libperfstat.h>

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

static int ret, tot, retrieved = 0;
static int interval = INTERVAL_DEFAULT, count = COUNT_DEFAULT;

/* To Check whether malloc is successful or not */
#define CHECK_FOR_MALLOC_NULL(X) {  if ((X) == NULL) {\
                                        perror ("malloc");\
                                        exit(2);\
                                     }\
                                 }

perfstat_protocol_t *pinfo, *qinfo;

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

/*
 * NAME: showusage
 *       Displays 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: display_protocol_statistics
 *       collects the statistics for all protocols and displays them
 *
 */

void display_protocol_statistics()
{
   int i;
   perfstat_id_t protid;

   /* check how many perfstat_protocol_t structures are available */
   if(collect_remote_node_stats) {
       strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
       nodeid.spec = NODENAME;
       tot = perfstat_protocol_node(&nodeid, NULL, sizeof(perfstat_protocol_t), 0);
   }
   else {
       tot = perfstat_protocol(NULL, NULL, sizeof(perfstat_protocol_t), 0);
   }
   if (tot <=0){
       perror("perfstat_protocol :");
       exit(1);
   }
   pinfo = (perfstat_protocol_t *)malloc(sizeof(perfstat_protocol_t) * tot);
   CHECK_FOR_MALLOC_NULL(pinfo);
	 
   qinfo = (perfstat_protocol_t *)malloc(sizeof(perfstat_protocol_t) * tot);
   CHECK_FOR_MALLOC_NULL(qinfo);

   /* retrieve first protocol usage information */
   if(collect_remote_node_stats) {
       strcpy(nodeid.name, FIRST_PROTOCOL);
       ret = perfstat_protocol_node(&nodeid, qinfo, sizeof(perfstat_protocol_t), tot);
   }
   else {
       /* set name to first protocol */
       strcpy(protid.name, FIRST_PROTOCOL);
       ret = perfstat_protocol(&protid, qinfo, sizeof(perfstat_protocol_t), tot);
   }
   if (ret <= 0){
       perror("perfstat_protocol:");
       exit(1);
   }

   while (count) {
       sleep (interval);
       if(collect_remote_node_stats) {
           strcpy(nodeid.name, FIRST_PROTOCOL);
           ret = perfstat_protocol_node(&nodeid, pinfo, sizeof(perfstat_protocol_t), tot);
       }
       else {
           strcpy(protid.name, FIRST_PROTOCOL);
           ret = perfstat_protocol(&protid, pinfo, sizeof(perfstat_protocol_t), tot);
       }
       if (ret <= 0){
	   perror("perfstat_protocol22:");
	   exit(1);
       }
       i = 0;
       while ( i < tot ){
           if (!strcmp(pinfo[i].name,"ip") || !strcmp(pinfo[i].name,"ipv6")) {
               printf("%10s %8s %8s %8s %8s\n", " Protocol ", "ipacket", "ierror", "opacket", "oerror");

     	       if (!strcmp(pinfo[i].name,"ip")){
                   printf("%10s %8llu %8llu %8llu %8llu\n", " ip ", (pinfo[i].u.ip.ipackets - qinfo[i].u.ip.ipackets),
								(pinfo[i].u.ip.ierrors - qinfo[i].u.ip.ierrors),
								(pinfo[i].u.ip.opackets - qinfo[i].u.ip.opackets),
								(pinfo[i].u.ip.oerrors - qinfo[i].u.ip.oerrors));
               }
               else{
	           printf("%10s %8llu %8llu %8llu %8llu\n", " ipv6 ", (pinfo[i].u.ipv6.ipackets - qinfo[i].u.ipv6.ipackets),
								(pinfo[i].u.ipv6.ierrors - qinfo[i].u.ipv6.ierrors),
								(pinfo[i].u.ipv6.opackets - qinfo[i].u.ipv6.opackets),
								(pinfo[i].u.ipv6.oerrors - qinfo[i].u.ipv6.oerrors));
               }
          } 
          else if (!strcmp(pinfo[i].name,"icmp") || !strcmp(pinfo[i].name,"icmpv6")) {
	       printf("%10s %8s %8s %8s\n", " Protocol ", "received", "sent", "errors");
               if (!strcmp(pinfo[i].name,"icmp")){
	           printf("%10s %8llu %8llu %8llu \n", " icmp ", (pinfo[i].u.icmp.received - qinfo[i].u.icmp.received),
							(pinfo[i].u.icmp.sent - qinfo[i].u.icmp.sent),
							(pinfo[i].u.icmp.errors - qinfo[i].u.icmp.errors));
               } 
	       else{
	   	   printf("%10s %8llu %8llu %8llu \n", " icmpv6 ", (pinfo[i].u.icmpv6.received - qinfo[i].u.icmpv6.received),
							(pinfo[i].u.icmpv6.sent - qinfo[i].u.icmpv6.sent),
							(pinfo[i].u.icmpv6.errors - qinfo[i].u.icmpv6.errors));
               }
          } 
	  else if (!strcmp(pinfo[i].name,"udp") || !strcmp(pinfo[i].name,"tcp")) {
               printf("%10s %8s %8s %8s\n", " Protocol ", "ipacket" , "ierror", "opacket");
               if (!strcmp(pinfo[i].name,"udp")){
                   printf("%10s %8llu %8llu %8llu \n", " udp ", (pinfo[i].u.udp.ipackets - qinfo[i].u.udp.ipackets),
							(pinfo[i].u.udp.ierrors - qinfo[i].u.udp.ierrors),
							(pinfo[i].u.udp.opackets - qinfo[i].u.udp.opackets));
               }
	       else{
		   printf("%10s %8llu %8llu %8llu \n", " tcp ", (pinfo[i].u.tcp.ipackets - qinfo[i].u.tcp.ipackets),
								(pinfo[i].u.tcp.ierrors - qinfo[i].u.tcp.ierrors),
								(pinfo[i].u.tcp.opackets - qinfo[i].u.tcp.opackets));
               }
          } 
          else if (!strcmp(pinfo[i].name,"rpc")) {
	       printf("%30s %30s\n", "client", "server");
               printf("%10s %8s %8s %8s %8s %8s %8s %8s %8s\n"," protocol ", "st.call", "st.badcl","dg.call","dg.badcl",
									   "st.call", "st.badcl","dg.call","dg.badcl");
	       printf("%10s %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n"," rpc ",(pinfo[i].u.rpc.client.stream.calls - qinfo[i].u.rpc.client.stream.calls),
									(pinfo[i].u.rpc.client.stream.badcalls - qinfo[i].u.rpc.client.stream.badcalls),
									(pinfo[i].u.rpc.client.dgram.calls - qinfo[i].u.rpc.client.dgram.calls),
									(pinfo[i].u.rpc.client.dgram.badcalls - qinfo[i].u.rpc.client.dgram.badcalls),
									(pinfo[i].u.rpc.server.stream.calls - qinfo[i].u.rpc.server.stream.calls),
									(pinfo[i].u.rpc.server.stream.badcalls - qinfo[i].u.rpc.server.stream.badcalls),
									(pinfo[i].u.rpc.server.dgram.calls - qinfo[i].u.rpc.server.dgram.calls),
									(pinfo[i].u.rpc.server.dgram.badcalls - qinfo[i].u.rpc.server.dgram.badcalls));
          } 
	  else if (!strcmp(pinfo[i].name,"nfs")) {
	       printf("%22s %20s\n","client","server");
	       printf("%10s %8s %8s %8s %8s %8s %8s\n"," protocol ","calls","badcalls","calls","badcalls","public_v2","public_v3");
	       printf("%10s %8llu %8llu %8llu %8llu %8llu %8llu\n"," nfs ", (pinfo[i].u.nfs.client.calls - qinfo[i].u.nfs.client.calls),
							(pinfo[i].u.nfs.client.badcalls - qinfo[i].u.nfs.client.badcalls),
							(pinfo[i].u.nfs.server.calls - qinfo[i].u.nfs.server.calls),
							(pinfo[i].u.nfs.server.badcalls - qinfo[i].u.nfs.server.badcalls),
							(pinfo[i].u.nfs.server.public_v2 - qinfo[i].u.nfs.server.public_v2),
							(pinfo[i].u.nfs.server.public_v3 - qinfo[i].u.nfs.server.public_v3));
          }
	  else if (!strcmp(pinfo[i].name,"nfsv2")) {
	       printf("%18s %8s\n","client","server");
	       printf("%10s %8s %8s \n"," protocol "," calls", "calls");
               printf("%10s %8llu %8llu \n"," nfsv2 ", (pinfo[i].u.nfsv2.client.calls - qinfo[i].u.nfsv2.client.calls),
							(pinfo[i].u.nfsv2.server.calls - qinfo[i].u.nfsv2.server.calls));

          } 
          else if (!strcmp(pinfo[i].name,"nfsv3")) {
	       printf("%18s %8s\n","client","server");
               printf("%10s %8s %8s \n"," protocol "," calls", "calls");
               printf("%10s %8llu %8llu \n"," nfsv3 ", (pinfo[i].u.nfsv3.client.calls - qinfo[i].u.nfsv3.client.calls),
							(pinfo[i].u.nfsv3.server.calls - qinfo[i].u.nfsv3.server.calls));
          }
       i++;
       }
    count--;
    memcpy( qinfo, pinfo, (tot * sizeof(perfstat_protocol_t)));
   }
}

/* 
 * NAME: main function 
 */

int main(int argc, char* argv[])
{
   int c, rc;

   /* Process the arguments */
   while ((c = getopt(argc, argv, "i:c:n:")) != EOF)
   {
       switch(c)
       {
           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);
       }
   }

   /* call the function to get all the protocol statistics */ 
   display_protocol_statistics();

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