Logo Search packages:      
Sourcecode: tcptrace version File versions  Download package

mod_traffic.c

/*
 * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
 *               2002, 2003, 2004
 *    Ohio University.
 *
 * ---
 * 
 * Starting with the release of tcptrace version 6 in 2001, tcptrace
 * is licensed under the GNU General Public License (GPL).  We believe
 * that, among the available licenses, the GPL will do the best job of
 * allowing tcptrace to continue to be a valuable, freely-available
 * and well-maintained tool for the networking community.
 *
 * Previous versions of tcptrace were released under a license that
 * was much less restrictive with respect to how tcptrace could be
 * used in commercial products.  Because of this, I am willing to
 * consider alternate license arrangements as allowed in Section 10 of
 * the GNU GPL.  Before I would consider licensing tcptrace under an
 * alternate agreement with a particular individual or company,
 * however, I would have to be convinced that such an alternative
 * would be to the greater benefit of the networking community.
 * 
 * ---
 *
 * This file is part of Tcptrace.
 *
 * Tcptrace was originally written and continues to be maintained by
 * Shawn Ostermann with the help of a group of devoted students and
 * users (see the file 'THANKS').  The work on tcptrace has been made
 * possible over the years through the generous support of NASA GRC,
 * the National Science Foundation, and Sun Microsystems.
 *
 * Tcptrace 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.
 *
 * Tcptrace 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 Tcptrace (in the file 'COPYING'); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 * 
 * Author:  Shawn Ostermann
 *          School of Electrical Engineering and Computer Science
 *          Ohio University
 *          Athens, OH
 *          ostermann@cs.ohiou.edu
 *          http://www.tcptrace.org/
 */
#include "tcptrace.h"
static char const GCC_UNUSED rcsid[] =
   "$Header: /usr/local/cvs/tcptrace/mod_traffic.c,v 5.16 2003/11/19 14:38:03 sdo Exp $";

#ifdef LOAD_MODULE_TRAFFIC

#include "mod_traffic.h"


/* info kept for each (active) port */
struct traffic_info {
    /* which port */
    u_short port;
    
    /* interval byte counters */
    PLINE line_nbytes;
    u_long nbytes;
    u_long ttlbytes;

    /* interval packet counters */
    PLINE line_npackets;
    u_long npackets;
    u_long ttlpackets;

    /* active connections */
    PLINE line_nactive;
    u_long nactive;
    u_long ttlactive;

    /* idle connections */
    PLINE line_nidle;
    u_long nidle;
    u_long ttlidle;

    /* open connections */
    PLINE line_nopen;
    u_long nopen;
    u_long ttlopen;

    /* instantaneous open connections */
    PLINE line_niopen;
    u_long n_i_open;
    u_long ttl_i_open;

    /* long-duration connections */
    PLINE line_nlong;
    u_long nlong;
    u_long ttllong;

    /* pureacks */
    PLINE line_pureacks;
    u_long npureacks;
    u_long ttlpureacks;

    /* which color is used for plotting */
    char *color;

    /* linked list of the one's we're using */
    struct traffic_info *next;
};
static struct traffic_info *traffichead = NULL;
#define NUM_PORTS 65536
static struct traffic_info **ports;  /* [NUM_PORTS] */
#define EXCLUDE_PORT ((void *)(-1))
#define INCLUDE_PORT (NULL)

/* name of the file that port data is dumped into */
#define PORT_FILENAME "traffic_byport.dat"
#define STATS_FILENAME "traffic_stats.dat"

/* additional info kept per connection */
struct conn_info {
    Bool wasactive;           /* was this connection active over the interval? */
    Bool wasopen;       /* was this this connection EVER open? */
    Bool isopen;        /* is this connection open now? */
    Bool islong;        /* is this a long-duration connection? */
    Bool halfopen;            /* for half open conns */
    struct traffic_info *pti1;      /* pointer to the port info for this one */
    struct traffic_info *pti2;      /* pointer to the port info for this one */
    struct conn_info *next;   /* next in the chain */

    u_int last_dupacks;       /* last value of dupacks I saw */
    u_int last_rexmits;       /* last value of rexmits I saw */
    u_int last_rtts;          /* last value of rtt counters I saw */
};
static struct conn_info *connhead = NULL;



/* plotter files that we keep open */
static PLOTTER plotter_bytes;
static PLOTTER plotter_packets;
static PLOTTER plotter_active;
static PLOTTER plotter_idle;
static PLOTTER plotter_open;
static PLOTTER plotter_openclose;
static PLOTTER plotter_i_open;
static PLOTTER plotter_loss;
static PLOTTER plotter_long;
static PLOTTER plotter_rtt;
static PLOTTER plotter_halfopen;
static PLOTTER plotter_pureacks;
static PLOTTER plotter_data;

#define  PLOTTER_BYTES_FILENAME           "traffic_bytes.xpl"
#define  PLOTTER_PACKETS_FILENAME   "traffic_packets.xpl"
#define  PLOTTER_ACTIVE_FILENAME    "traffic_active.xpl"
#define  PLOTTER_OPEN_FILENAME            "traffic_open.xpl"
#define  PLOTTER_OPENCLOSE_FILENAME "traffic_openclose.xpl"
#define  PLOTTER_I_OPEN_FILENAME    "traffic_i_open.xpl"
#define  PLOTTER_LOSS_FILENAME            "traffic_loss.xpl"
#define  PLOTTER_LONG_FILENAME            "traffic_long.xpl"
#define  PLOTTER_RTT_FILENAME       "traffic_rtt.xpl"
#define  PLOTTER_HALFOPEN_FILENAME  "traffic_halfopen.xpl"
#define  PLOTTER_PUREACKS_FILENAME  "traffic_pureacks.xpl"
#define  PLOTTER_IDLE_FILENAME            "traffic_idle.xpl"
#define  PLOTTER_DATA_FILENAME            "traffic_data.xpl"

/* argument flags */
static float age_interval = 15.0;  /* 15 seconds by default */
static Bool doplot_bytes = FALSE;
static Bool doplot_packets = FALSE;
static Bool doplot_active = FALSE;
static Bool doplot_open = FALSE;
static Bool doplot_openclose = FALSE;
static Bool doplot_i_open = FALSE;
static Bool doplot_loss = FALSE;
static Bool doplot_long = FALSE;
static Bool doplot_rtt = FALSE;
static Bool doplot_halfopen = FALSE;
static Bool doplot_pureacks = FALSE;
static Bool doplot_idle = FALSE;
static Bool doplot_data = FALSE;
static int longconn_duration = 60;


/* local routines */
static struct traffic_info *MakeTrafficRec(u_short port);
static void MakeTrafficLines(struct traffic_info *pti);
static struct conn_info *MakeConnRec(void);
static void AgeTraffic(void);
static struct traffic_info *FindPort(u_short port);
static void IncludePorts(unsigned firstport, unsigned lastport);
static void ExcludePorts(unsigned firstport, unsigned lastport);
static void CheckPortNum(unsigned portnum);
static char *PortName(int port);
static void ParseArgs(char *argstring);
static void DoplotIOpen(int port, Bool fopen);


/* info for opens and closes graphs */
static PLINE line_num_closes;
static PLINE line_num_opens;
static PLINE line_open_conns;
static PLINE line_num_halfopens;
static int num_closes = 0;
static int num_opens = 0;
static int ttl_num_opens = 0;
static int ttl_num_closes = 0;
static int open_conns = 0;
static int num_halfopens = 0;

/* info for total byte counters */
static PLINE line_data_nonrexmit;
static PLINE line_data_all;
static u_llong data_nbytes_nonrexmit;
static u_llong data_nbytes_all;

/* info for the loss events graph */
static PLINE line_dupacks;
static PLINE line_rexmits;
static u_long dupacks;
static u_long ttl_dupacks;
static u_long rexmits;
static u_long ttl_rexmits;

/* info for the RTT graph */
static PLINE line_rtt_avg;
static PLINE line_rtt_min;
static PLINE line_rtt_max;
static float rtt_ttl;         /* in msecs */
static float ttl_rtt_ttl;     /* in msecs */
static int rtt_min = -1;      /* in msecs */
static int rtt_max = -1;      /* in msecs */
static int rtt_samples;
static int ttl_rtt_samples;
static u_int rtt_minvalid = 0;      /* minimum RTT to consider (ms) */
static u_int rtt_maxvalid = 0xffffffff; /* maximum RTT to consider (ms) */


/* local debugging flag */
static int ldebug = 0;


static void
CheckPortNum(
    unsigned portnum)
{
    if (portnum >= NUM_PORTS) {
      fprintf(stderr,"mod_traffic: Invalid port number '%d'\n", portnum);
      traffic_usage();
      exit(-1);
    }
}


static void
ExcludePorts(
    unsigned firstport,
    unsigned lastport)
{
    CheckPortNum(firstport);
    CheckPortNum(lastport);

    if (ldebug)
      printf("mod_traffic: excluding ports [%d-%d]\n", firstport, lastport);

    while (firstport <= lastport)
      ports[firstport++] = EXCLUDE_PORT;
}


static void
IncludePorts(
    unsigned firstport,
    unsigned lastport)
{
    CheckPortNum(firstport);
    CheckPortNum(lastport);

    if (ldebug)
      printf("mod_traffic: including ports [%d-%d]\n", firstport, lastport);

    while (firstport <= lastport)
      ports[firstport++] = INCLUDE_PORT;
}



/* Mostly as a module example, here's a plug in that records TRAFFIC info */
int
traffic_init(
    int argc,
    char *argv[])
{
    int i;
    int enable=0;
    char *args = NULL;

    for (i=1; i < argc; ++i) {
      if (!argv[i])
          continue;  /* argument already taken by another module... */
      if (strncmp(argv[i],"-x",2) == 0) {
          if (strncasecmp(argv[i]+2,"traffic",sizeof("traffic")-1) == 0) {
            /* I want to be called */
            args = argv[i]+(sizeof("-xtraffic")-1);
            enable = 1;
            printf("mod_traffic: characterizing traffic\n");
            argv[i] = NULL;
          }
      }
    }

    if (!enable)
      return(0);  /* don't call me again */

    /* init the data storage structure */
    ports = MallocZ(NUM_PORTS*sizeof(struct traffic_info *));

    ports[0] = MakeTrafficRec(0);

    /* parse the encoded args */
    ParseArgs(args);

    /* open the output files */
    if (doplot_packets)
      plotter_packets =
          new_plotter(NULL,
                  PLOTTER_PACKETS_FILENAME,
                  "packets per second over time by port",
                  "time","packets/second",
                  NULL);
    if (doplot_bytes)
      plotter_bytes =
          new_plotter(NULL,
                  PLOTTER_BYTES_FILENAME,
                  "bytes per second over time by port",
                  "time","bytes/second",
                  NULL);
    if (doplot_active)
      plotter_active =
          new_plotter(NULL,
                  PLOTTER_ACTIVE_FILENAME,
                  "active connections over time by port",
                  "time","active connections",
                  NULL);
    if (doplot_idle)
      plotter_idle =
          new_plotter(NULL,
                  PLOTTER_IDLE_FILENAME,
                  "idle connections over time by port",
                  "time","idle connections",
                  NULL);
    if (doplot_open)
      plotter_open =
          new_plotter(NULL,
                  PLOTTER_OPEN_FILENAME,
                  "open connections over time by port",
                  "time","open connections",
                  NULL);
    if (doplot_i_open)
      plotter_i_open =
          new_plotter(NULL,
                  PLOTTER_I_OPEN_FILENAME,
                  "open connections over time by port - instantaneous",
                  "time","number of connections",
                  NULL);
    if (doplot_openclose) {
      plotter_openclose =
          new_plotter(NULL,
                  PLOTTER_OPENCLOSE_FILENAME,
                  "connections opened and closed over time",
                  "time","number of connections",
                  NULL);
      line_num_opens = new_line(plotter_openclose, "Number Opens", "green");
      line_num_closes = new_line(plotter_openclose, "Number Closes", "red");
      line_open_conns = new_line(plotter_openclose, "Total Open", "blue");
    }
    if (doplot_halfopen) {
      plotter_halfopen =
          new_plotter(NULL,
                  PLOTTER_HALFOPEN_FILENAME,
                  "half open connections over time",
                  "time","number of half open connections",
                  NULL);
      line_num_halfopens = new_line(plotter_halfopen,
                              "Halfopen Conns", "green");
    }
    if (doplot_pureacks) {
      plotter_pureacks =
          new_plotter(NULL,
                  PLOTTER_PUREACKS_FILENAME,
                  "pure acks (no data) per second over time",
                  "time","pureacks/second",
                  NULL);
    }

    if (doplot_loss) {
      plotter_loss =
          new_plotter(NULL,
                  PLOTTER_LOSS_FILENAME,
                  "packet loss per second over time",
                  "time","events/second",
                  NULL);
      line_dupacks = new_line(plotter_loss, "Triple Dupacks", "yellow");
      line_rexmits = new_line(plotter_loss, "Retransmits", "blue");
    }

    if (doplot_rtt) {
      plotter_rtt =
          new_plotter(NULL,
                  PLOTTER_RTT_FILENAME,
                  "RTT over time",
                  "time","RTT (msecs)",
                  NULL);
      line_rtt_min = new_line(plotter_rtt, "Min RTT", "green");
      line_rtt_max = new_line(plotter_rtt, "Max RTT", "red");
      line_rtt_avg = new_line(plotter_rtt, "Average RTT", "blue");
    }

    if (doplot_data) {
      plotter_data =
          new_plotter(NULL,
                  PLOTTER_DATA_FILENAME,
                  "Total Data Sent Over Time",
                  "time","total bytes",
                  NULL);
      line_data_all = new_line(plotter_data, "All Data", "blue");
      line_data_nonrexmit = new_line(plotter_data, "Non-Rexmitted Data", "red");
    }

    if (doplot_long) {
      char title[100];
      snprintf(title,sizeof(title),"connections still open after %d seconds\n",
            longconn_duration);
      plotter_long =
          new_plotter(NULL,
                  PLOTTER_LONG_FILENAME,
                  title,
                  "time","number of connections",
                  NULL);
    }

    /* we don't want the normal output */
    printsuppress = TRUE;

    /* create any lines that I want to draw */
    MakeTrafficLines(ports[0]);

    /* init the graphs and etc... */
    AgeTraffic();

    return(1);    /* TRUE means call traffic_read and traffic_done later */
}


/* return the record for traffic on this port */
static struct traffic_info *
FindPort(
    u_short port)
{
    struct traffic_info *pti;

    /* port "0" means "all", but we don't need to treat it as a special case */

    /* see what's there now */
    pti = ports[port];

    /* see if it's "excluded" */
    if ((port != 0) && (pti == EXCLUDE_PORT))
      return(NULL);

    /* make a new one if there's a NULL there */
    if (!pti) {
      pti = MakeTrafficRec(port);
      /* create any lines that I want to draw */
      MakeTrafficLines(pti);
    }

    return(pti);
}





static struct traffic_info *
MakeTrafficRec(
    u_short port)
{
    struct traffic_info *pti;

    pti = MallocZ(sizeof(struct traffic_info));

    if (ldebug>10)
      printf("MakeTrafficRec(%d) called\n", (int)port);

    /* init */
    pti->port = port;

    /* chain it in (at head of list) */
    pti->next = traffichead;
    traffichead = pti;

    /* add to lookup array */
    ports[port] = pti;

    return(pti);
}


static void
MakeTrafficLines(
    struct traffic_info *pti)
{
    char *portname;
    static int nextcolor = 0;

    /* map port number to name for printing */
    portname = (pti->port==0)?"total":strdup(PortName(pti->port));

    /* pick color */
    pti->color = ColorNames[nextcolor % NCOLORS];
    ++nextcolor;

    /* create the lines that we sometimes use */
    if (doplot_bytes)
      pti->line_nbytes = new_line(plotter_bytes, portname, pti->color);
    if (doplot_packets) 
      pti->line_npackets = new_line(plotter_packets, portname, pti->color);
    if (doplot_active)
      pti->line_nactive = new_line(plotter_active, portname, pti->color);
    if (doplot_idle)
      pti->line_nidle = new_line(plotter_idle, portname, pti->color);
    if (doplot_open)
      pti->line_nopen = new_line(plotter_open, portname, pti->color);
    if (doplot_long)
      pti->line_nlong = new_line(plotter_long, portname, pti->color);
    if (doplot_i_open)
      pti->line_niopen = new_line(plotter_i_open, portname, pti->color);
    if (doplot_pureacks)
      pti->line_pureacks = new_line(plotter_pureacks, portname, pti->color);
}



static struct conn_info *
MakeConnRec(void)
{
    struct conn_info *pci;

    pci = MallocZ(sizeof(struct conn_info));

    /* chain it in (at head of list) */
    pci->next = connhead;
    connhead = pci;

    return(pci);
}


void
traffic_read(
    struct ip *pip,           /* the packet */
    tcp_pair *ptp,            /* info I have about this connection */
    void *plast,        /* past byte in the packet */
    void *mod_data)           /* connection info for this one */
{
    struct tcphdr *ptcp = (struct tcphdr *) ((char *)pip + 4*IP_HL(pip));
    struct traffic_info *pti1 = FindPort(ntohs(ptcp->th_sport));
    struct traffic_info *pti2 = FindPort(ntohs(ptcp->th_dport));
    u_long bytes = ntohs(pip->ip_len);
    static timeval last_time = {0,0};
    struct conn_info *pci = mod_data;
    int was_rexmit = 0;

    /* if neither port is interesting, then ignore this one */
    if (!pti1 && !pti2) {
      return;
    }

    /* OK, this connection is now active */
    pci->wasactive = 1;

    /* check to see if it's really "open" (traffic in both directions) */
    if (!pci->wasopen) {
      if ((ptp->a2b.packets > 0) && (ptp->b2a.packets > 0)) {
          /* bidirectional: OK, we'll call it open */
          pci->wasopen = 1;
          pci->isopen = 1;
          ++num_opens;
          ++ttl_num_opens;
          ++open_conns;

          /* instantaneous opens and closes */
          if (doplot_i_open) {
            DoplotIOpen(ntohs(ptcp->th_dport), TRUE);
            DoplotIOpen(ntohs(ptcp->th_sport), TRUE);
            DoplotIOpen(0, TRUE);
          }
      }
    }

    /* add to port-specific counters */
    if (pti1) {
      pti1->nbytes += bytes;
      pti1->npackets += 1;
    }
    if (pti2) {
      pti2->nbytes += bytes;
      pti2->npackets += 1;
    }

    /* add to GLOBAL counters */
    ports[0]->nbytes += bytes;
    ports[0]->npackets += 1;
    ports[0]->npureacks += 1;

    /* see if we're closing it */
    if (RESET_SET(ptcp) ||
      (FIN_SET(ptcp) && /* find in BOTH directions */
       ((ptp->a2b.fin_count>0) && (ptp->b2a.fin_count>0)))) {
      if (pci->isopen) {
          pci->isopen = 0;
          ++num_closes;
          --open_conns;

          /* instantaneous opens and closes */
          if (doplot_i_open) {
            DoplotIOpen(ntohs(ptcp->th_dport), FALSE);
            DoplotIOpen(ntohs(ptcp->th_sport), FALSE);
            DoplotIOpen(0, FALSE);
          }
      }
    }

    /* half open conns */
    if (FIN_SET(ptcp)) {
      if ((ptp->a2b.fin_count>0) && (ptp->b2a.fin_count>0)) {
          if (pci->halfopen) {
            /* fully closed now */
            --num_halfopens;
            pci->halfopen = 0;
          }
      } else if (!pci->halfopen) {
            /* half open now */
            ++num_halfopens;
            pci->halfopen = 1;
      }
    }

    /* check losses */
    if (pci->last_dupacks != ptp->a2b.rtt_triple_dupack+
      ptp->b2a.rtt_triple_dupack) {
      pci->last_dupacks = ptp->a2b.rtt_triple_dupack+
          ptp->b2a.rtt_triple_dupack;
      ++dupacks;
      ++ttl_dupacks;
    }
    if (pci->last_rexmits != ptp->a2b.rexmit_pkts+ptp->b2a.rexmit_pkts) {
      pci->last_rexmits = ptp->a2b.rexmit_pkts+ptp->b2a.rexmit_pkts;
      was_rexmit = 1;
      ++rexmits;
      ++ttl_rexmits;
    }


    /* add to total data counters */
    data_nbytes_all += bytes;
    if (!was_rexmit)
      data_nbytes_nonrexmit += bytes;
    

    /* RTT stats */
    if (ACK_SET(ptcp)) {
      tcb *ptcb;
      int rtt;

      /* see which of the 2 TCB's this goes with */
      if (ptp->addr_pair.a_port == ntohs(ptcp->th_dport))
          ptcb = &ptp->a2b;
      else
          ptcb = &ptp->b2a;

      /* check the rtt counter of the last sample */
      rtt = ptcb->rtt_last / 1000.0;
 
      if ((pci->last_rtts != ptcb->rtt_count + ptcb->rtt_amback) &&
          (ptcb->rtt_last != 0.0) &&
          (rtt > rtt_minvalid) && (rtt <= rtt_maxvalid)) {

          /* sample is only valid when one of these counters is higher */
          pci->last_rtts = ptcb->rtt_count + ptcb->rtt_amback;

          /* keep stats */
          rtt_ttl += rtt;
          ttl_rtt_ttl += rtt;
          ++rtt_samples;
          ++ttl_rtt_samples;

          /* also, remember min and max */
          if ((rtt_max == -1) || (rtt_max < rtt))
            rtt_max = rtt;
          if ((rtt_min == -1) || (rtt_min > rtt))
            rtt_min = rtt;

          if (ldebug > 9)
            printf("Rtt: %d,  min:%d,  max:%d\n",
                   rtt, rtt_min, rtt_max);
      }
    }


    /* see if this is now "long duration" */
    if (!pci->islong) {
      int etime_msecs = elapsed(ptp->first_time,current_time);
      if (etime_msecs/1000000 > longconn_duration) {
          pci->islong = 1;
      }
    }

    /* count "pure acks" (no data) */
    if (ACK_SET(ptcp)) {
      int tcp_length, tcp_data_length;
      tcp_length = getpayloadlength(pip, plast);
      tcp_data_length = tcp_length - (4 * TH_OFF(ptcp));
      if (tcp_data_length == 0) {
          if (pti1) {
            ++pti1->npureacks;
          }
          if (pti2) {
            ++pti2->npureacks;
          }
      }
    }


    /* determine elapsed time and age the samples */
    if (elapsed(last_time,current_time)/1000000.0 > age_interval) {
      AgeTraffic();
      last_time = current_time;
    }
}


static char *
PortName(
    int port)
{
    static char buf[20];

    if (port == 0)
      return("total");

    snprintf(buf,sizeof(buf),"%d",port);
    return(buf);
}


static void
AgeTraffic(void)
{
    struct traffic_info *pti;
    struct conn_info *pci;
    static timeval last_time = {0,0};
    float etime;
    int ups;                  /* units per second */

    /* first time doesn't count */
    if (ZERO_TIME(&last_time)) {
      last_time = current_time;
      return;
    }

    /* check elapsed time */
    etime = elapsed(last_time, current_time);
    if (ldebug>1)
      printf("AgeTraffic called, elapsed time is %.3f seconds\n", etime/1000000);
    if (etime == 0.0)
      return;

    /* roll the open/active/long connections into the port records */
    for (pci=connhead; pci; pci=pci->next) {
      if (pci->wasactive) {
          if (pci->pti1)
            ++pci->pti1->nactive;
          if (pci->pti2)
            ++pci->pti2->nactive;
          pci->wasactive = 0;
          ++ports[0]->nactive;
      }
      if (pci->isopen) {
          if (pci->pti1)
            ++pci->pti1->nopen;
          if (pci->pti2)
            ++pci->pti2->nopen;
          ++ports[0]->nopen;
          if (pci->islong) {
            if (pci->pti1)
                ++pci->pti1->nlong;
            if (pci->pti2)
                ++pci->pti2->nlong;
            ++ports[0]->nlong;
          }

          if (!pci->wasactive) {
            /* open and !active ==> IDLE */
            if (pci->pti1)
                ++pci->pti1->nidle;
            if (pci->pti2)
                ++pci->pti2->nidle;
            ++ports[0]->nidle;
          }
      }
    }
    

    /* ============================================================ */
    /* plot halfopen conns */
    if (doplot_halfopen) {
      /* draw lines */
      extend_line(line_num_halfopens,current_time, num_halfopens);
    }


    /* ============================================================ */
    /* plot connection activity */
    /* opens */
    if (doplot_openclose) {
      /* draw lines */
      extend_line(line_num_opens,current_time, num_opens);
      extend_line(line_num_closes,current_time, num_closes);
      extend_line(line_open_conns,current_time, open_conns);

      /* reset interval counters */
       
// Counting ttl_num_opens instantaneously as and when num_opens is incremented,
// so that ttl_num_opens is printed properly in traffic_stats.dat even 
// when the -C(openclose) option is not given.
// Hence commenting off the following line. - Mani, 4 Aug 2003.
//    ttl_num_opens += num_opens;
      ttl_num_closes += num_closes;
      num_opens = 0;
      num_closes = 0;
    }


    /* ============================================================ */
    /* report of loss events */
    if (doplot_loss) {
      /* convert to events/second */
      /* sdo bugfix - Wed May 12, 1999 - round UP!! */
      dupacks = (dupacks+age_interval-1)/age_interval;
      rexmits = (rexmits+age_interval-1)/age_interval;

      /* draw lines */
      extend_line(line_dupacks,current_time, dupacks);
      extend_line(line_rexmits,current_time, rexmits);

      /* reset interval counters */
      dupacks = 0;
      rexmits = 0;
    }


    /* ============================================================ */
    /* report of RTT */
    if (doplot_rtt && (rtt_samples > 0)) {
      int rtt_avg;

      /* convert to average rtt */
      rtt_avg = (int)((rtt_ttl/(float)rtt_samples));

      /* draw lines */
      extend_line(line_rtt_avg, current_time, rtt_avg);
      if (rtt_min != -1)
          extend_line(line_rtt_min, current_time, rtt_min);
      if (rtt_max != -1)
          extend_line(line_rtt_max, current_time, rtt_max);

      /* reset interval counters */
      rtt_ttl = 0;
      rtt_samples = 0;
      rtt_min = -1;
      rtt_max = -1;
    }


    /* ============================================================ */
    /* report of total data */
    if (doplot_data) {
      extend_line(line_data_all, current_time, data_nbytes_all);
      extend_line(line_data_nonrexmit, current_time, data_nbytes_nonrexmit);
    }

    /* ============================================================ */
    /* print them out */
    for (pti=traffichead; pti; pti=pti->next) {
      if (ldebug>1)
          printf("  Aging Port %u   bytes: %lu  packets: %lu\n",
               pti->port, pti->nbytes, pti->npackets);

      /* plot bytes */
      if (doplot_bytes) {
          /* convert to units per second */
          ups = (int)((float)pti->nbytes * 1000000.0 / etime);

          /* plot it */
          extend_line(pti->line_nbytes,current_time, ups);
      }

      /* plot packets */
      if (doplot_packets) {
          /* convert to units per second */
          ups = (int)((float)pti->npackets * 1000000.0 / etime);

          /* plot it */
          extend_line(pti->line_npackets,current_time, ups);
      }



      /* plot active connections */
      if (doplot_active) {
          /* plot it */
          extend_line(pti->line_nactive,current_time, pti->nactive);
      }

      /* plot idle connections */
      if (doplot_idle) {
          /* plot it */
          extend_line(pti->line_nidle,current_time, pti->nidle);
      }


      /* plot open connections */
      if (doplot_open) {
          /* plot it */
          extend_line(pti->line_nopen,current_time, pti->nopen);
      }

      /* plot long-duration */
      if (doplot_long) {
          extend_line(pti->line_nlong,current_time, pti->nlong);
      }

      /* plot pureacks */
      if (doplot_pureacks) {
          /* convert to units per second */
          ups = (int)((float)pti->npureacks * 1000000.0 / etime);

          extend_line(pti->line_pureacks, current_time, ups);
      }
    }

    /* zero them out */
    for (pti=traffichead; pti; pti=pti->next) {
      pti->ttlbytes += pti->nbytes;
      pti->ttlpackets += pti->npackets;
      pti->ttlpureacks += pti->npureacks;

      pti->nbytes = 0;
      pti->nlong = 0;
      pti->npackets = 0;
      pti->nactive = 0;
      pti->nidle = 0;
      pti->nopen = 0;
      pti->npureacks = 0;
    }

    last_time = current_time;
}


void  
traffic_done(void)
{
    struct traffic_info *pti;
    struct conn_info *pci;
    double etime = elapsed(first_packet,last_packet);
    int etime_secs = etime / 1000000.0;
    MFILE *pmf;
    int i;

    /* roll the active connections into the port records */
    for (pci=connhead; pci; pci=pci->next) {
      if (pci->pti1)
          ++pci->pti1->ttlactive;
      if (pci->pti2)
          ++pci->pti2->ttlactive;
      ++ports[0]->ttlactive;
    }

    AgeTraffic();

    pmf = Mfopen(PORT_FILENAME,"w");
    printf("Dumping port statistics into file %s\n", PORT_FILENAME);

    /* dump out the data */
    Mfprintf(pmf,"Overall totals by port\n");
    for (i=0; i < NUM_PORTS; ++i) {
      pti = ports[i];
      if ((pti != EXCLUDE_PORT) && (pti != INCLUDE_PORT)) {
          if (i == 0)
            Mfprintf(pmf,"TOTAL        ");
          else
            Mfprintf(pmf,"Port %5u   ", pti->port);
          Mfprintf(pmf,"\
bytes: %12lu  pkts: %10lu  conns: %8lu  tput: %8lu B/s\n",
                 pti->ttlbytes,
                 pti->ttlpackets,
                 pti->ttlactive,
                 pti->ttlbytes / etime_secs);
      }
    }
    Mfclose(pmf);

    /* dump specific stats */
    pmf = Mfopen(STATS_FILENAME,"w");
    printf("Dumping overall statistics into file %s\n", STATS_FILENAME);

    pti = ports[0];

    Mfprintf(pmf, "\n\nOverall Statistics over %d seconds (%s):\n",
           etime_secs, elapsed2str(etime));

    /* ttl bytes */
    Mfprintf(pmf, "%" FS_ULL " ttl bytes sent, %.3f bytes/second\n",
           data_nbytes_all,
           (float)data_nbytes_all / ((float)etime_secs));

    /* ttl bytes (nonrexmit)*/
    Mfprintf(pmf, "%" FS_ULL " ttl non-rexmit bytes sent, %.3f bytes/second\n",
           data_nbytes_nonrexmit,
           (float)data_nbytes_nonrexmit / ((float)etime_secs));

    /* ttl bytes (nonrexmit)*/
    Mfprintf(pmf, "%" FS_ULL " ttl rexmit bytes sent, %.3f bytes/second\n",
           data_nbytes_all - data_nbytes_nonrexmit,
           (float)(data_nbytes_all - data_nbytes_nonrexmit) /
           ((float)etime_secs));

    /* ttl packets */
    Mfprintf(pmf, "%u packets sent, %.3f packets/second\n",
           pti->ttlpackets,
           (float)pti->ttlpackets / ((float)etime_secs));

    /* connections opened */
    Mfprintf(pmf, "%u connections opened, %.3f conns/second\n",
           ttl_num_opens,
           (float)ttl_num_opens / ((float)etime_secs));

    /* dupacks */
    Mfprintf(pmf, "%u dupacks sent, %.3f dupacks/second\n",
           ttl_dupacks,
           (float)ttl_dupacks / ((float)etime_secs));

    /* rexmits */
    Mfprintf(pmf, "%u rexmits sent, %.3f rexmits/second\n",
           ttl_rexmits,
           (float)ttl_rexmits / ((float)etime_secs));

    /* RTT */
    Mfprintf(pmf, "average RTT: %.3f msecs\n",
           ttl_rtt_ttl / (float)ttl_rtt_samples);


    Mfclose(pmf);

    printf("Plotting performed at %.3f second intervals\n", age_interval);

}




void *
traffic_newconn(
    tcp_pair *ptp)
{
    struct conn_info *pci;

    pci = MakeConnRec();
    pci->pti1 = FindPort(ptp->addr_pair.a_port);
    pci->pti2 = FindPort(ptp->addr_pair.b_port);

    return(pci);
}


void
traffic_usage(void)
{
    printf("\t-xtraffic\"[ARGS]\"\tprint info about overall traffic\n");
    printf("\
\t   module argument format:\n\
\t       -iS          set statistics interval to S (float) seconds, default 15.0\n\
\t       -pP          include information on port P\n\
\t       -pP1-P2      include information on ports in the range [P1-P2]\n\
\t       -p-P         exclude information on port P\n\
\t       -p-P1-P2     exclude information on ports in the range [P1-P2]\n\
\t       -pSPEC,SPEC  commas chain together specs\n\
\t       -G           generate all graphs\n\
\t       -A           generate the 'active connections' graph\n\
\t       -B           generate the 'bytes per second' graph\n\
\t       -C           generate the 'opens and closes' graph\n\
\t       -H           generate the 'halfopen connections' graph\n\
\t       -K           generate the 'pure acKs/second' graph\n\
\t       -L           generate the 'losses per second' graph\n\
\t       -O           generate the 'open connections' graph\n\
\t       -I           generate the 'instantaneous open connections' graph\n\
\t       -P           generate the 'packets per second' graph\n\
\t       -Q           generate the 'idle (Quiet) connections' graph\n\
\t       -R[MIN[-MAX]]generate the 'round trip time' graph\n\
\t                    with args, ignore samples outside MIN to MAX (in ms)\n\
\t       -T           generate the 'total data' graph\n\
\t       -D[SECS]     generate the 'long duration connection' graph\n\
\t                default definition of 'long' is 60 seconds\n\
\t       -d           enable local debugging in this module\n\
\t     Examples\n\
\t       -xtraffic\" -p23\"            only port 23\n\
\t       -xtraffic\" -p1-1023\"        only ports 1-1023\n\
\t       -xtraffic\"-p1-1023,-10-20 -L -O\"  only ports 1-1023, but exclude ports 10-20\n\
\t     With no ports specification, all ports are gathered.  With ANY\n\
\t     spec, all ports are initially EXCLUDED\n\
");
}

static void
ParseArgs(char *argstring)
{
    int argc;
    char **argv;
    static int excluded = 0;
    int i;
    char *pch;
    
    /* make sure there ARE arguments */
    if (!(argstring && *argstring))
      return;

    /* break the string into normal arguments */
    StringToArgv(argstring,&argc,&argv);

    /* check the module args */
    for (i=1; i < argc; ++i) {
      float interval;
      if (ldebug > 1)
          printf("Checking argv[%d]: '%s'\n", i, argv[i]);
      if (strcmp(argv[i],"-d") == 0) {
          ++ldebug;
      } else if (sscanf(argv[i],"-i%f", &interval) == 1) {
          age_interval = interval;
          if (ldebug)
            printf("mod_traffic: setting age interval to %.3f seconds\n",
                   age_interval);
      } else if (strcmp(argv[i],"-G") == 0) {
          doplot_active = TRUE;
          doplot_idle = TRUE;
          doplot_data = TRUE;
          doplot_bytes = TRUE;
          doplot_loss = TRUE;
          doplot_long = TRUE;
          doplot_open = TRUE;
          doplot_halfopen = TRUE;
          doplot_openclose = TRUE;
          doplot_i_open = TRUE;
          doplot_packets = TRUE;
          doplot_pureacks = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating all graphs\n");
      } else if (strcmp(argv[i],"-A") == 0) {
          doplot_active = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'active' graph into '%s'\n",
                  PLOTTER_ACTIVE_FILENAME);
      } else if (strcmp(argv[i],"-B") == 0) {
          doplot_bytes = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'bytes' graph into '%s'\n",
                  PLOTTER_BYTES_FILENAME);
      } else if (strcmp(argv[i],"-H") == 0) {
          doplot_halfopen = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'halfopen' graph into '%s'\n",
                  PLOTTER_HALFOPEN_FILENAME);
      } else if (strcmp(argv[i],"-Q") == 0) {
          doplot_idle = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'idle' graph into '%s'\n",
                  PLOTTER_IDLE_FILENAME);
      } else if (strcmp(argv[i],"-K") == 0) {
          doplot_pureacks = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'pureacks' graph into '%s'\n",
                  PLOTTER_PUREACKS_FILENAME);
      } else if (strcmp(argv[i],"-L") == 0) {
          doplot_loss = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'loss' graph into '%s'\n",
                  PLOTTER_LOSS_FILENAME);
      } else if (strcmp(argv[i],"-T") == 0) {
          doplot_data = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'total data' graph into '%s'\n",
                  PLOTTER_DATA_FILENAME);
      } else if (strncmp(argv[i],"-D",2) == 0) {
          doplot_long = TRUE;
          if (strlen(argv[i]) > 2) {
            /* grab the number */
            longconn_duration = atoi(argv[i]+2);
            if (longconn_duration <= 0) {
                fprintf(stderr,"bad time value for -LN '%s'\n",
                      argv[i]);
                exit(-1);
            }

          }
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'long duration' graph (%d secs) into '%s'\n",
                  longconn_duration,
                  PLOTTER_LONG_FILENAME);
      } else if (strcmp(argv[i],"-O") == 0) {
          doplot_open = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'open' graph into '%s'\n",
                  PLOTTER_OPEN_FILENAME);
      } else if (strcmp(argv[i],"-C") == 0) {
          doplot_openclose = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'openclose' graph into '%s'\n",
                  PLOTTER_OPENCLOSE_FILENAME);
      } else if (strcmp(argv[i],"-I") == 0) {
          doplot_i_open = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'instantaneous openclose' graph into '%s'\n",
                  PLOTTER_I_OPEN_FILENAME);
      } else if (strcmp(argv[i],"-P") == 0) {
          doplot_packets = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'packets' graph into '%s'\n",
                  PLOTTER_PACKETS_FILENAME);
      } else if (strncmp(argv[i],"-R",2) == 0) {
          int nargs;
          doplot_rtt = TRUE;
          if (ldebug)
            fprintf(stderr,
                  "mod_traffic: generating 'rtt' graph into '%s'\n",
                  PLOTTER_RTT_FILENAME);
          /* check for valid RTT range args */
          nargs = sscanf(argv[i],"-R%d-%d", &rtt_minvalid,
                     &rtt_maxvalid);
          switch (nargs) {
            case 2: {         /* 2 args is min and max */
              /* sanity check */
              if (rtt_maxvalid <= rtt_minvalid) {
                  fprintf(stderr,
                        "mod_traffic: Out of order min-max range for -R '%s'\n",
                        argv[i]);
                  traffic_usage();
                  exit(-1);
              }
              break;
            }
            case 1: {         /* 1 args in min rtt */
              /* sanity check */
              if (rtt_maxvalid <= rtt_minvalid) {
                  fprintf(stderr,
                        "mod_traffic: Out of order min-max range for -R '%s'\n",
                        argv[i]);
                  traffic_usage();
                  exit(-1);
              }
              break;
            }
            case 0:           /* no args, that's OK */
            case -1:          /* (means the same as 0) */
            break;
            default:          /* illegal args  */
            fprintf(stderr,
                  "mod_traffic: Invalid min-max range for -R '%s'\n",
                  argv[i]);
            traffic_usage();
            exit(-1);
            break;
          }
      } else if (strncmp(argv[i],"-p",2) == 0) {
          pch = argv[i]+2;
          while (pch && *pch) {
            char *pch_next;
            unsigned port1, port2;

            if ((pch_next = strchr(pch,',')) != NULL) {
                *pch_next = '\00';
                ++pch_next;
            }

            if (!excluded) {
                ExcludePorts(1,NUM_PORTS-1);
                excluded = 1;
            }

            if (sscanf(pch,"-%u-%u", &port1, &port2) == 2) {
                ExcludePorts(port1,port2);
            } else if (sscanf(pch,"%u-%u", &port1, &port2) == 2) {
                IncludePorts(port1,port2);
            } else if (sscanf(pch,"-%u", &port1) == 1) {
                ExcludePorts(port1,port1);
            } else if (sscanf(pch,"%u", &port1) == 1) {
                IncludePorts(port1,port1);
            } else {
                fprintf(stderr,"mod_traffic: Invalid port specification string '%s'\n", pch);
                traffic_usage();
                exit(-1);
            }

            pch = pch_next;
          }
      } else {
          fprintf(stderr,"Traffic module: bad argument '%s'\n",
                argv[i]);
          exit(-1);
      }
    }
}

static void
DoplotIOpen(int port, Bool fopen)
{
    struct traffic_info *pti;

    /* just for this port */
    if ((pti = FindPort(port)) == NULL)
      return;

    if (fopen)
      ++pti->n_i_open;
    else
      --pti->n_i_open;

    extend_line(pti->line_niopen, current_time, pti->n_i_open);
}

#endif /* LOAD_MODULE_TRAFFIC */

Generated by  Doxygen 1.6.0   Back to index