From: Martin Mares Date: Thu, 19 Jun 2003 12:41:49 +0000 (+0000) Subject: Add histograms and recovery after SIGINT. X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=99757a8b6e3037dc466b06c9e9bc521283efa4ae;p=netgrind.git Add histograms and recovery after SIGINT. --- diff --git a/netgrind/Makefile b/netgrind/Makefile index a176ff4..18a6706 100644 --- a/netgrind/Makefile +++ b/netgrind/Makefile @@ -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 index 0000000..53495b1 --- /dev/null +++ b/netgrind/histogram.c @@ -0,0 +1,132 @@ +/* + * Netgrind -- Histograms + * + * (c) 2003 Martin Mares + * + * 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 +#include +#include + +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); + } +} diff --git a/netgrind/netgrind.c b/netgrind/netgrind.c index c7680f7..da02074 100644 --- a/netgrind/netgrind.c +++ b/netgrind/netgrind.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -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 Dump connections to a given directory\n\ -D Dump connections with more details\n\ -f Apply filter expression\n\ +-h Write packet histogram to \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, diff --git a/netgrind/netgrind.h b/netgrind/netgrind.h index df1af42..fae6071 100644 --- a/netgrind/netgrind.h +++ b/netgrind/netgrind.h @@ -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);