]> mj.ucw.cz Git - netgrind.git/commitdiff
Add histograms and recovery after SIGINT.
authorMartin Mares <mj@ucw.cz>
Thu, 19 Jun 2003 12:41:49 +0000 (12:41 +0000)
committerMartin Mares <mj@ucw.cz>
Thu, 19 Jun 2003 12:41:49 +0000 (12:41 +0000)
netgrind/Makefile
netgrind/histogram.c [new file with mode: 0644]
netgrind/netgrind.c
netgrind/netgrind.h

index a176ff4540606e3dde68bae38879f9c517a5ed7d..18a670655c8c3955619ed6648b061e8c2cedf90b 100644 (file)
@@ -1,6 +1,6 @@
 DIRS+=netgrind
 PROGS+=obj/netgrind/netgrind
-NG_OBJS=netgrind.o pkt.o link.o ip.o tcp.o save.o http.o
+NG_OBJS=netgrind.o pkt.o link.o ip.o tcp.o save.o http.o histogram.o
 
 obj/netgrind/netgrind: $(addprefix obj/netgrind/,$(NG_OBJS)) $(LIBSH)
 obj/netgrind/netgrind: LIBS+=-lpcap
diff --git a/netgrind/histogram.c b/netgrind/histogram.c
new file mode 100644 (file)
index 0000000..53495b1
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *     Netgrind -- Histograms
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU General Public License.
+ */
+
+#include "lib/lib.h"
+#include "netgrind/pkt.h"
+#include "netgrind/netgrind.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static FILE *hist_file;
+static list hist_list;
+static uns hist_bucket_start, hist_threshold;
+static uns hist_bucket_size = 60;
+
+struct hist_entry {
+  node n;
+  byte *name;
+  enum {
+    HE_STATS,
+    HE_INT
+  } type;
+  union {
+    struct {
+      struct pkt_stats *var;
+      struct pkt_stats last_state;
+    } st;
+    struct {
+      int *var;
+      int last_state;
+    } in;
+  } u;
+};
+
+void histogram_init(byte *name)
+{
+  hist_file = fopen(name, "w");
+  if (!hist_file)
+    die("Unable to open %s: %m", name);
+  list_init(&hist_list);
+}
+
+void histogram_add_stat(byte *name, struct pkt_stats *stat)
+{
+  struct hist_entry *e = xmalloc_zero(sizeof(*e));
+  list_add_tail(&hist_list, &e->n);
+  e->name = name;
+  e->type = HE_STATS;
+  e->u.st.var = stat;
+}
+
+void histogram_add_int(byte *name, int *var)
+{
+  struct hist_entry *e = xmalloc_zero(sizeof(*e));
+  list_add_tail(&hist_list, &e->n);
+  e->name = name;
+  e->type = HE_INT;
+  e->u.in.var = var;
+}
+
+static void hist_header(void)
+{
+  struct hist_entry *e;
+  fprintf(hist_file, "# time");
+  WALK_LIST(e, hist_list)
+    fprintf(hist_file, "\t%s", e->name);
+  fputc('\n', hist_file);
+}
+
+static void hist_print(void)
+{
+  struct hist_entry *e;
+  fprintf(hist_file, "%d", hist_bucket_start);
+  WALK_LIST(e, hist_list)
+    switch (e->type)
+      {
+      case HE_STATS:
+       fprintf(hist_file, "\t%Ld(%Ld)",
+               e->u.st.var->packets - e->u.st.last_state.packets,
+               e->u.st.var->bytes - e->u.st.last_state.bytes);
+       break;
+      case HE_INT:
+       fprintf(hist_file, "\t%d", *e->u.in.var - e->u.in.last_state);
+       break;
+      default:
+       ASSERT(0);
+      }
+  fputc('\n', hist_file);
+}
+
+void histogram_step(uns time)
+{
+  if (!hist_file || time < hist_threshold)
+    return;
+  if (!hist_bucket_start)
+    hist_header();
+  else
+    hist_print();
+  hist_bucket_start = time - (time % hist_bucket_size);
+  hist_threshold = hist_bucket_start + hist_bucket_size;
+
+  struct hist_entry *e;
+  WALK_LIST(e, hist_list)
+    switch (e->type)
+      {
+      case HE_STATS:
+       e->u.st.last_state = *e->u.st.var;
+       break;
+      case HE_INT:
+       e->u.in.last_state = *e->u.in.var;
+       break;
+      default:
+       ASSERT(0);
+      }
+}
+
+void histogram_cleanup(void)
+{
+  if (hist_file)
+    {
+      if (hist_threshold)
+       hist_print();
+      fclose(hist_file);
+    }
+}
index c7680f7d8882d1cb5a7b2cfbfb2cfaadc9f25044..da020748a0340ca46fb3aef1cd01fab29db68a3d 100644 (file)
@@ -16,6 +16,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <getopt.h>
+#include <signal.h>
+#include <setjmp.h>
 #include <netinet/in.h>
 
 #include <pcap.h>
@@ -31,6 +33,13 @@ void die(byte *msg, ...)
   exit(1);
 }
 
+static volatile int stop_signal;
+
+static void sigint_handler(int arg UNUSED)
+{
+  stop_signal = 1;
+}
+
 /*** MANUAL MULTIPLEXER ***/
 
 static void mux_open(struct flow *f, u64 when)
@@ -60,6 +69,7 @@ static struct pkt_stats stat_pcap_incomplete, stat_pcap_in;
 
 static uns in_count, start_sec;
 static u64 last_timestamp;
+static jmp_buf stop_jump;
 
 static int link_setup_handler(int dlt)
 {
@@ -72,6 +82,9 @@ static int link_setup_handler(int dlt)
 
 static void got_pcap_packet(u_char *userdata UNUSED, const struct pcap_pkthdr *hdr, const u_char *pkt)
 {
+  if (stop_signal)
+    longjmp(stop_jump, 1);
+  histogram_step((uns) hdr->ts.tv_sec);
   stat_pcap_in.packets++;
   stat_pcap_in.bytes += hdr->len;
   if (hdr->caplen != hdr->len)
@@ -108,6 +121,7 @@ static void usage(void)
 -d <dir>       Dump connections to a given directory\n\
 -D <dir>       Dump connections with more details\n\
 -f <filter>    Apply filter expression\n\
+-h <file>      Write packet histogram to <file>\n\
 -s             Dump connection summary\n\
 -t             Calculate statistics only\n\
 -w             TCP: Wait for ACK before processing packets\n\
@@ -115,17 +129,19 @@ static void usage(void)
   exit(1);
 }
 
+static int max_packets = -1;
+static byte *filter = NULL;
+
 int main(int argc, char **argv)
 {
   char errbuf[PCAP_ERRBUF_SIZE];
   pcap_t *pcap;
   int c, dlt;
-  int max_packets = -1;
-  byte *filter = NULL;
   struct bpf_program filter_prog;
+  byte *histogram = NULL;
 
   tcp_default_appl = &appl_mux;
-  while ((c = getopt(argc, argv, "ac:d:D:f:stw")) >= 0)
+  while ((c = getopt(argc, argv, "ac:d:D:f:h:stw")) >= 0)
     switch (c)
       {
       case 'a':
@@ -145,6 +161,9 @@ int main(int argc, char **argv)
       case 'f':
        filter = optarg;
        break;
+      case 'h':
+       histogram = optarg;
+       break;
       case 'w':
        tcp_wait_for_ack = 1;
        break;
@@ -161,6 +180,34 @@ int main(int argc, char **argv)
     usage();
 
   tcp_init();
+  if (histogram)
+    {
+      histogram_init(histogram);
+      histogram_add_stat("PcapIn", &stat_pcap_in);
+      histogram_add_stat("PcapIncomp", &stat_pcap_incomplete);
+      histogram_add_stat("LinkIn", &stat_link_in);
+      histogram_add_stat("LinkDwarf", &stat_link_dwarf);
+      histogram_add_stat("LinkUnkn", &stat_link_unknown);
+      histogram_add_stat("LinkArp", &stat_link_arp);
+      histogram_add_stat("IPIn", &stat_ip_in);
+      histogram_add_stat("IPBad", &stat_ip_invalid);
+      histogram_add_stat("IPUnint", &stat_ip_uninteresting);
+      histogram_add_stat("IPFrag", &stat_ip_fragmented);
+      histogram_add_stat("IPBadSum", &stat_ip_badsum);
+      histogram_add_stat("TCPIn", &stat_tcp_in);
+      histogram_add_stat("TCPBad", &stat_tcp_invalid);
+      histogram_add_stat("TCPBadSum", &stat_tcp_badsum);
+      histogram_add_stat("TCPUnmatch", &stat_tcp_unmatched);
+      histogram_add_stat("TCPOnClosed", &stat_tcp_on_closed);
+      histogram_add_stat("TCPBadState", &stat_tcp_bad_state);
+      histogram_add_int("FlowsTotal", &cnt_tcp_flows);
+      histogram_add_int("FlowsClosed", &cnt_tcp_causes[CAUSE_CLOSE]);
+      histogram_add_int("FlowsReset", &cnt_tcp_causes[CAUSE_RESET]);
+      histogram_add_int("FlowsTimeout", &cnt_tcp_causes[CAUSE_TIMEOUT]);
+      histogram_add_int("FlowsDoomsday", &cnt_tcp_causes[CAUSE_DOOMSDAY]);
+      histogram_add_int("FlowsBad", &cnt_tcp_causes[CAUSE_CORRUPT]);
+    }
+  signal(SIGINT, sigint_handler);
 
   while (optind < argc)
     {
@@ -177,12 +224,24 @@ int main(int argc, char **argv)
          pcap_setfilter(pcap, &filter_prog);
          pcap_freecode(&filter_prog);
        }
-      if (pcap_loop(pcap, max_packets, got_pcap_packet, NULL) < 0)
-       die("Capture failed: %s", pcap_geterr(pcap));
+      if (!setjmp(stop_jump))
+       {
+         if (pcap_loop(pcap, max_packets, got_pcap_packet, NULL) < 0)
+           {
+             fprintf(stderr, "Capture failed: %s\n", pcap_geterr(pcap));
+             break;
+           }
+       }
+      else
+       {
+         fprintf(stderr, "Interrupted\n");
+         break;
+       }
       pcap_close(pcap);
       optind++;
     }
   tcp_cleanup(last_timestamp);
+  histogram_cleanup();
   printf("# Netgrind statistics:\n");
   printf("# Pcap: %Ld(%Ld) in, %Ld(%Ld) incomplete\n",
         stat_pcap_in.packets, stat_pcap_in.bytes,
index df1af428e22bcaa5b088256dee4ea0f5bcaf1101..fae60718b22b5349e3a4606762d0088e2e7be6a1 100644 (file)
@@ -103,3 +103,11 @@ void format_timestamp(byte *buf, u64 time);
 /* http.c */
 
 extern struct appl_hooks appl_http;
+
+/* histogram.c */
+
+void histogram_init(byte *name);
+void histogram_add_stat(byte *name, struct pkt_stats *stat);
+void histogram_add_int(byte *name, int *var);
+void histogram_step(uns time);
+void histogram_cleanup(void);