--- /dev/null
+/*
+ * 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);
+ }
+}
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
+#include <signal.h>
+#include <setjmp.h>
#include <netinet/in.h>
#include <pcap.h>
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)
static uns in_count, start_sec;
static u64 last_timestamp;
+static jmp_buf stop_jump;
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)
-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\
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':
case 'f':
filter = optarg;
break;
+ case 'h':
+ histogram = optarg;
+ break;
case 'w':
tcp_wait_for_ack = 1;
break;
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)
{
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,