/*  -*- Mode: C;  -*- */

/******************************************************************************
*                                                                             *
*   Copyright 2005 University of Cambridge Computer Laboratory.               *
*                                                                             *
*   This file is part of Nprobe.                                              *
*                                                                             *
*   Nprobe is free software; you can redistribute it and/or modify            *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation; either version 2 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   Nprobe is distributed in the hope that it will be useful,                 *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*   GNU General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with Nprobe; if not, write to the Free Software                     *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
*                                                                             *
******************************************************************************/


#ifndef _COUNTERS_H_
#define _COUNTERS_H_


#define FHDR_DATA_SZ 1024

struct fhdr 
{
  unsigned int magic;
  char vers_pre;
  int vers_n;
  /* run time flags */
  int how_collected; 
  int compressed;
  int quick_close;
  int accept_nosyn;
  unsigned int tcp_timeout;
  unsigned int tcp_seq_timeout;
  unsigned int udp_timeout;
  int ncpus;
  int hz;
  int pgsz;
  unsigned int rep_fsz, dump_fsz;
  int spare[8];		/* adjust as necessary */
  char data[FHDR_DATA_SZ];   /* for offline input records dump file name */
};
typedef struct fhdr fhdr_t;

/* constants for how_collected */
#define TCPDUMP_COLL 0
#define NPROBE_COLL 1

/* constants for compression */
#define NOT_COMPRESSED 0
#define LZO_COMPRESSED 1

#define WAN_MAGIC 0x57414E44	/* = 'WAND' */

/*
 * A set of counters for dropped packets, etc. 
 */

struct ctr 
{
  ulonglong pkts;
  ulonglong octs;
#if !defined SWIG_ONLY && defined __ia64__
} __attribute__ ((packed));
#else
};
#endif
typedef struct ctr ctr_t;

struct max_ctr 
{
  unsigned int current;
  unsigned int max;
#if !defined SWIG_ONLY && defined __ia64__
} __attribute__ ((packed));
#else
};
#endif
typedef struct max_ctr max_ctr_t;

struct max_ctrs 
{
  struct max_ctr hostconns;
  struct max_ctr tconns;
  struct max_ctr uconns;
  struct max_ctr trans;
  struct max_ctr heldpkts;		/* struct heldpackets used */
  struct max_ctr buffers_held;	/* packet records used */
  struct max_ctr saved_hdr_buffs;
  struct max_ctr links_buffs;
  struct max_ctr links_chars;
  struct max_ctr ns_recs;
  struct max_ctr tag_bufs;
  struct max_ctr spare[21];	/* ADJUST as necessary */
  double wire_bw;		/* over some period (2s) */
  double http_bw;		/* over some period (2s) */
  unsigned int int_get;		/* scheduling rather than network us*/
  unsigned int min_tcp_seq_to;	/* minimum tcp seq timeo - forced ms*/
  unsigned int int_fetch;		/* scheduling rather than network us*/
  unsigned int spare_ui;
  double dbl_spare[9];	/* ADJUST as necessary */
#if !defined SWIG_ONLY && defined __ia64__
} __attribute__ ((packed));
#else
};
#endif


typedef struct max_ctrs max_ctrs_t;

/* stuff we want to carry over file cycles i.e. accumulative */
struct run_ctr
{
  struct ctr wire_all; 
  struct ctr IP_all;

  struct ctr TCP_all;
  struct ctr HTTP_all;
  struct ctr HTML_all;
  struct ctr UDP_all;

  struct ctr IP_ulen_all;
  struct ctr notIP_all;

  struct ctr sparectrs[19];	/* ADJUST as necessary */ 
  unsigned int tot_records;
  unsigned int rep_blks_all;
  unsigned int dump_blks_all;
  ulonglong rep_bytes_all;
  ulonglong dump_bytes_all;

  unsigned int sparelongs[19];	/* ADJUST as necessary */
#if !defined SWIG_ONLY && defined __ia64__
} __attribute__ ((packed));
#else
};
#endif
typedef struct run_ctr run_ctrs_t;

struct counters 
{
  fhdr_t fh;

  /* all incoming */
  struct ctr wire;

  /* traffic types seen */
  struct ctr TRAFF_IP;

  struct ctr TRAFF_TCP;
  struct ctr TRAFF_UDP;
  struct ctr TRAFF_ICMP;
  struct ctr TRAFF_ICMP_UNREACH;
  struct ctr TRAFF_IP_OTHER;
  struct ctr TRAFF_IP_SPARE[9];	/* ADJUST as necessary */
  
  /* TCP traffic*/
  struct ctr TRAFF_TCP_HTTP;
  struct ctr TRAFF_TCP_FTP_DATA;
  struct ctr TRAFF_TCP_FTP;
  struct ctr TRAFF_TCP_TELNET;
  struct ctr TRAFF_TCP_SMTP;
  struct ctr TRAFF_TCP_POP3;
  struct ctr TRAFF_TCP_NNTP;
  struct ctr TRAFF_TCP_NETBIOS_SSN;
  struct ctr TRAFF_TCP_RTSP;
  struct ctr TRAFF_TCP_PNM;
  struct ctr TRAFF_TCP_OTHER;
  struct ctr TRAFF_TCP_TEST;
  struct ctr TRAFF_TCP_BGP;
  struct ctr TRAFF_TCP_SPARE[16];	/* ADJUST as necessary */

  /* UDP traffic  */
  struct ctr TRAFF_UDP_DNS;
  struct ctr TRAFF_UDP_NFS;
  struct ctr TRAFF_UDP_ICQ;
  struct ctr TRAFF_UDP_OTHER;
  struct ctr TRAFF_UDP_SPARE[23];	/* ADJUST as necessary */

  /* drops */
  struct ctr MACHdr;
  struct ctr wrong_encaps;
  struct ctr wrong_llc_type;
  struct ctr notIP;
  struct ctr IPHdr;
  struct ctr IPversion;
  struct ctr IPFrag;
  struct ctr IPLen;
  struct ctr IPHdr_opts;
  struct ctr IPSum;
  struct ctr UDPHdr;
  struct ctr UDPSum;
  struct ctr not_TCPUDP;
  struct ctr TCPHdr;
  struct ctr TCPSum;
  struct ctr port_filtered_out;
  struct ctr Nprobe_errpkts;
  struct ctr TCPHdr_opts;
  struct ctr startup_nosyn;
  struct ctr SYN_too_late;
  struct ctr serv_orig;
  struct ctr filter;
  struct ctr HTTP_port;
  struct ctr ICMP_len;
  struct ctr ffilter;
  struct ctr IP_ulen;		/* iplen < 0 */
  struct ctr drops_spare[17];	/* ADJUST as necessary */

  /* info */
  struct ctr TCPDump_trunc;
  struct ctr IPLen_media_minpkt;
  struct ctr IP_pkt_too_long;
  struct ctr held_pkts;
  struct ctr held_epkts;
  struct ctr frag_hdr_pkts;     /* # pkts. containing fragmented HTTP hdrs */
  struct ctr html_parsed;
  struct ctr infoctr_spare[23];	/* ADJUST as necessary */
  unsigned int frag_hdr_trans;	/* # transactions affected*/
  unsigned int frag_hdr_trans_ok;	/* # eventually parsed ok */
  ulonglong dump_bytes_written;
  ulonglong dump_blks_dumped;
  ulonglong rep_bytes_written;
  ulonglong rep_blks_dumped;
  ulonglong infolongspare[25];	/* ADJUST as necessary */

  /* general */
  ulonglong host_flows;
  ulonglong tcpconns;
  ulonglong udpconns;
  ulonglong buffers_got;
  ulonglong buffers_released;

  ulonglong tcp_timeo;
  ulonglong tcp_seq_timeo;
  ulonglong tcp_full_close;
  ulonglong tcp_eff_close;
  ulonglong tcp_forced_close;
  ulonglong tcp_quick_close;
  ulonglong tcp_end_close;
  ulonglong tcp_one_way_only;
  ulonglong tcp_seq_timeo_forced;
  ulonglong tcp_seq_timeo_ack;
  ulonglong tcp_seq_timeo_ql;
  ulonglong tcp_maverick_SYN;
  ulonglong tcp_duplicate_SYN;
  ulonglong tcp_forced_alt;
  ulonglong tcp_opt_fail;

  ulonglong udp_one_way_only;
  ulonglong udp_timeo;
  ulonglong udp_open;

  unsigned int buf_alloc_fails;
  unsigned int nic_fails;

  ulonglong tcp_cli_only;
  ulonglong tcp_serv_only;

  ulonglong tcp_payload_dropped;

  ulonglong generallongspare[12];	/* ADJUST as necessary */

  tmval start, stop;	/* times this file cycle */
  unsigned int nrecords;

  /* HTTP */
  unsigned int http_errs[N_HTTP_ERRS];
  ulonglong http_trans;		/* # trans started */
  /* eventual disposal */
  ulonglong http_trans_comp;	/* got all of obj requested */
  ulonglong http_trans_incomp;	/* not got all of obj requested */
  ulonglong http_trans_fin;		/* finished but not object requested */
  ulonglong http_trans_cli_only;	/* only client side seen */
  ulonglong http_trans_dummy;	/* dummy trans XX each way XX */
  ulonglong http_trans_err;	        /* error encountered  XX each way XX*/
  ulonglong http_trans_lost_synch;    /* lost synchronisation  XX each way XX*/
  ulonglong http_trans_resynch;	/* Recovered synch XX each way XX*/
  ulonglong http_trans_timeinvalid; /* something wrong with timing info */
  ulonglong http_trans_chunked; /* chunked transfer encodings */
  ulonglong http_trans_trailer_perm; /* invitation to use trailers */
  ulonglong http_trans_trailer; /* trailer fields used */
  ulonglong http_trans_serv_only;	/* only server side seen */
  ulonglong http_dump_objects_dropped;/* dump object failed - no available fd */
  ulonglong httplongspare[4];	/* ADJUST as necessary */
  struct ctr http_unsynched;
  struct ctr httpctr_spare[10];	/* ADJUST as necessary */

  /* Other services */
  struct ctr servctr_spare[50];	/* ADJUST as necessary */
  ulonglong servlongspare[50];	/* ADJUST as necessary */

  max_ctrs_t max_ctrs;
  run_ctrs_t run_ctrs;
#if !defined SWIG_ONLY && defined __ia64__
} __attribute__ ((packed));
#else
};
#endif
typedef struct counters counters_t;

#ifndef SWIG
extern counters_t counters;
void ncpus_and_freq();
#endif

/****************************************************************************/


#define BUMP_CTR(field)   \
MACRO_BEGIN                \
  counters.field++;\
MACRO_END

#define BUMP_CTR_N(field, n)   \
MACRO_BEGIN                \
  counters.field+=(n);\
MACRO_END

#define BUMP_DROPS(field)   \
MACRO_BEGIN                \
  counters.field.pkts++;\
  counters.field.octs+=pp->len;\
MACRO_END

#define BUMP_INFO(field)   \
MACRO_BEGIN                \
  counters.field.pkts++;\
  counters.field.octs+=pp->len;\
MACRO_END

#define BUMP_GLOBAL(field)   \
MACRO_BEGIN                \
  counters.field.pkts++;\
  counters.field.octs+=pp->len;\
MACRO_END

#define BUMP_SPECIFIC_OCTS(field, len)   \
MACRO_BEGIN                \
  counters.field.pkts++;\
  counters.field.octs+=(len);\
MACRO_END

#define MAX_CTR(field)   \
MACRO_BEGIN                \
  counters.max_ctrs.field.current++;\
  counters.max_ctrs.field.max = MAX(counters.max_ctrs.field.current, counters.max_ctrs.field.max); \
MACRO_END

#define MAX_CTR_N(field, n)   \
MACRO_BEGIN                \
  counters.max_ctrs.field.current += n;\
  counters.max_ctrs.field.max = MAX(counters.max_ctrs.field.current, counters.max_ctrs.field.max); \
MACRO_END

#define DROP_MAX_CTR(field)   \
MACRO_BEGIN                \
  counters.max_ctrs.field.current--;\
MACRO_END

#define DROP_MAX_CTR_N(field, n)   \
MACRO_BEGIN                \
  counters.max_ctrs.field.current -= n;\
MACRO_END

/* used for max counters on file cycle */
#define MAX_CTR_RESET(field)     \
MACRO_BEGIN                \
  cp->max_ctrs.field.max = cp->max_ctrs.field.current;\
MACRO_END

/****************************************************************************/

/* Zeroing out counter types */

#define ZERO_CTRS(field)              \
MACRO_BEGIN                \
  cp->field.pkts = 0ULL;  \
  cp->field.octs = 0ULL;  \
MACRO_END

#define ZERO_UINT32(field)              \
MACRO_BEGIN                \
  cp->field = 0UL;  \
MACRO_END

#define ZERO_MAX_CTR(field)              \
MACRO_BEGIN                \
  cp->max_ctrs.field.max = 0U;   \
  cp->max_ctrs.field.current = 0U;  \
MACRO_END 

#define ZERO_RUN_CTR(field)              \
MACRO_BEGIN                \
  cp->run_ctrs.field.pkts = 0ULL;\
  cp->run_ctrs.field.octs = 0ULL;  \
MACRO_END  

/*****************************************************************************/

/* Adding counter types */

#define ADD_CTRS(field)              \
MACRO_BEGIN                \
  acc->field.pkts += add->field.pkts;  \
  acc->field.octs += add->field.octs;  \
MACRO_END

#define ADD_VAL(field)              \
MACRO_BEGIN                \
  acc->field += add->field;  \
MACRO_END

#define ACCUM_MAX_CTR(field)              \
MACRO_BEGIN                \
  acc->max_ctrs.field.max =    \
       MAX(acc->max_ctrs.field.max, add->max_ctrs.field.max);  \
MACRO_END 

#define ACCUM_RUN_CTR(field)              \
MACRO_BEGIN                \
  acc->run_ctrs.field.pkts = MAX(acc->run_ctrs.field.pkts,   \
                                   add->run_ctrs.field.pkts);\
  acc->run_ctrs.field.octs = MAX(acc->run_ctrs.field.octs,   \
                                   add->run_ctrs.field.octs);  \
MACRO_END 

/****************************************************************************/  



#define PCENT(x, y) (y) != 0 ?         \
                             ((float)(x)*100)/(float)(y) : 0.0



#ifndef MACRO_BEGIN
#define MACRO_BEGIN do {
#define MACRO_END    } while (0)
#endif

#define REP(file, fmt, args...)           \
MACRO_BEGIN              \
fprintf((file), fmt, ## args);    \
MACRO_END

#define REP_L(file, fmt, args...)   \
MACRO_BEGIN              \
  fprintf((file), "%s ", leader); \
  fprintf((file), fmt, ## args);  \
MACRO_END


#if defined FINAL_REPORT || defined REPORT || defined WREAD

 
#define SHOW_CTR(file, field, name, percentof, base)              \
MACRO_BEGIN                \
  if (counters->field.pkts)     \
    {                          \
      REP_L((file), "\t%-18s %10llu pkts %10llu octets  %4.2f%%/%4.2f%% of %s\n", name, \
              counters->field.pkts, counters->field.octs,       \
              PCENT(counters->field.pkts, counters->percentof.pkts),        \
              PCENT(counters->field.octs, counters->percentof.octs),  \
              base); \
    }                      \
MACRO_END


#define SHOW_TTYPE(file, field, name, percentof_pkts, percentof_octs, base)  \
MACRO_BEGIN                \
  if ((pkts = counters->field.pkts))     \
    {                          \
       octs = counters->field.octs;    \
  REP_L(file, "\t\t%-10s: %10.0f pkts %10.0f octets  %4.2f%%/%4.2f%% of %s\n", #name, pkts, octs, PCENT(pkts, percentof_pkts), PCENT(octs, percentof_octs), #base);     \
    }                      \
MACRO_END



#define EARLIEST(tv1, tv2)   \
  ((tv1).tv_sec < (tv2).tv_sec ? (tv1)  \
           : (tv1).tv_sec > (tv2).tv_sec ? (tv2)  \
                 : (tv1).tv_usec < (tv2).tv_usec ? (tv1) : (tv2))

#define LATEST(tv1, tv2)   \
  ((tv1).tv_sec > (tv2).tv_sec ? (tv1)  \
           : (tv1).tv_sec < (tv2).tv_sec ? (tv2)  \
                 : (tv1).tv_usec > (tv2).tv_usec ? (tv1) : (tv2))


/*
 * counters.c 
 */

void tvsub(tmval *tdiff, tmval *t1, tmval *t0);
ll_t utvsub(tmval *t1, tmval *t0);

void report_counters(counters_t *counters, FILE *f, char *leader);
void add_ctrs(counters_t *acc, counters_t *add);

#endif /* if defined FINAL_REPORT || defined REPORT || defined WREAD */

void counters_init(counters_t *cp, tmval *start, unsigned int magic);
void reset_counters(counters_t *counters, tmval *cycle_time);
void accumulate_run_counters(counters_t *counters);


#endif /* _COUNTERS_H_ */

/*
 * end counters.h 
 */
