2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2009, 2010 Daniel Borkmann.
5 * Subject to the GPL, version 2.
7 * A tiny tool to provide top-like reliable networking statistics.
8 * Why? Well, some time ago I used iptraf to display network traffic
9 * statistics. During that time and probably also today, they are
10 * using libpcap to collect statistics. Well, bad idea since this
11 * will give you false statistics on high I/O load. Therefore, ifpps
12 * reads out the 'real' kernel statistics, so things your NIC sees
13 * and not some userland library.
15 * He had all the injured air of a liar suspected when for once he
16 * has told the truth, or part of it.
18 * -- The Lord of the Rings, On Gollum,
19 * Chapter 'The Black Gate is Closed'.
27 #include <sys/socket.h>
40 * TODO: Cleanups, this got quite a hack over time.
43 #define TERM_MODE_NORMAL 1
44 #define TERM_MODE_CSV 2
45 #define TERM_MODE_CSV_HDR 4
47 #define USER_HZ sysconf(_SC_CLK_TCK)
50 unsigned long rx_bytes
;
51 unsigned long rx_packets
;
52 unsigned long rx_drops
;
53 unsigned long rx_errors
;
54 unsigned long rx_fifo
;
55 unsigned long rx_frame
;
56 unsigned long rx_multi
;
57 unsigned long tx_bytes
;
58 unsigned long tx_packets
;
59 unsigned long tx_drops
;
60 unsigned long tx_errors
;
61 unsigned long tx_fifo
;
62 unsigned long tx_colls
;
63 unsigned long tx_carrier
;
66 unsigned long *irqs_srx
;
67 unsigned long *irqs_stx
;
68 unsigned long *cpu_user
;
69 unsigned long *cpu_nice
;
70 unsigned long *cpu_sys
;
71 unsigned long *cpu_idle
;
72 unsigned long *cpu_iow
;
75 unsigned long procs_run
;
76 unsigned long procs_iow
;
81 int wifi_link_qual_max
;
82 int wifi_signal_level
;
89 volatile sig_atomic_t sigint
= 0;
91 static const char *short_options
= "d:t:vhcCHlp";
92 static const struct option long_options
[] = {
93 {"dev", required_argument
, NULL
, 'd'},
94 {"interval", required_argument
, NULL
, 't'},
95 {"loop", no_argument
, NULL
, 'l'},
96 {"term", no_argument
, NULL
, 'c'},
97 {"promisc", no_argument
, NULL
, 'p'},
98 {"csv", no_argument
, NULL
, 'C'},
99 {"csv-tablehead", no_argument
, NULL
, 'H'},
100 {"version", no_argument
, NULL
, 'v'},
101 {"help", no_argument
, NULL
, 'h'},
105 static void signal_handler(int number
)
118 static int rxtx_stats(const char *ifname
, struct ifstat
*s
)
124 FILE *fp
= fopen("/proc/net/dev", "r");
126 whine("Cannot open /proc/net/dev!\n");
131 ptr
= fgets(buf
, sizeof(buf
), fp
);
132 ptr
= fgets(buf
, sizeof(buf
), fp
);
134 memset(buf
, 0, sizeof(buf
));
135 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
136 buf
[sizeof(buf
) -1] = 0;
138 if (strstr(buf
, ifname
) == NULL
)
146 ret
= sscanf(ptr
, "%lu%lu%lu%lu%lu%lu%lu%*u%lu%lu%lu%lu%lu%lu%lu",
147 &s
->rx_bytes
, &s
->rx_packets
, &s
->rx_errors
,
148 &s
->rx_drops
, &s
->rx_fifo
, &s
->rx_frame
,
150 &s
->tx_bytes
, &s
->tx_packets
, &s
->tx_errors
,
151 &s
->tx_drops
, &s
->tx_fifo
, &s
->tx_colls
,
158 memset(buf
, 0, sizeof(buf
));
166 static int wifi_stats(const char *ifname
, struct ifstat
*s
)
169 struct iw_statistics ws
;
171 ret
= wireless_sigqual(ifname
, &ws
);
173 /* We don't want to trouble in case of eth* */
178 s
->wifi_bitrate
= wireless_bitrate(ifname
);
179 s
->wifi_signal_level
= adjust_dbm_level(ws
.qual
.updated
& IW_QUAL_DBM
,
181 s
->wifi_noise_level
= adjust_dbm_level(ws
.qual
.updated
& IW_QUAL_DBM
,
183 s
->wifi_link_qual
= ws
.qual
.qual
;
184 s
->wifi_link_qual_max
= wireless_rangemax_sigqual(ifname
);
189 static void stats_check_alloc(struct ifstat
*s
)
191 int cpus
= get_number_cpus();
193 if (s
->irqs_len
!= get_number_cpus()) {
194 if (s
->irqs
) xfree(s
->irqs
);
195 if (s
->irqs_srx
) xfree(s
->irqs_srx
);
196 if (s
->irqs_stx
) xfree(s
->irqs_stx
);
197 if (s
->cpu_user
) xfree(s
->cpu_user
);
198 if (s
->cpu_nice
) xfree(s
->cpu_nice
);
199 if (s
->cpu_sys
) xfree(s
->cpu_sys
);
200 if (s
->cpu_idle
) xfree(s
->cpu_idle
);
201 if (s
->cpu_iow
) xfree(s
->cpu_iow
);
203 s
->irqs_srx
= xzmalloc(sizeof(*(s
->irqs_srx
)) * cpus
);
204 s
->irqs_stx
= xzmalloc(sizeof(*(s
->irqs_stx
)) * cpus
);
205 s
->irqs
= xzmalloc(sizeof(*(s
->irqs
)) * cpus
);
206 s
->cpu_user
= xzmalloc(sizeof(*(s
->cpu_user
)) * cpus
);
207 s
->cpu_nice
= xzmalloc(sizeof(*(s
->cpu_nice
)) * cpus
);
208 s
->cpu_sys
= xzmalloc(sizeof(*(s
->cpu_sys
)) * cpus
);
209 s
->cpu_idle
= xzmalloc(sizeof(*(s
->cpu_idle
)) * cpus
);
210 s
->cpu_iow
= xzmalloc(sizeof(*(s
->cpu_iow
)) * cpus
);
215 static int irq_sstats(struct ifstat
*s
)
221 FILE *fp
= fopen("/proc/softirqs", "r");
223 whine("Cannot open /proc/softirqs!\n");
227 stats_check_alloc(s
);
229 memset(buff
, 0, sizeof(buff
));
230 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
231 buff
[sizeof(buff
) - 1] = 0;
233 if ((ptr
= strstr(buff
, "NET_TX:")) == NULL
) {
234 ptr
= strstr(buff
, "NET_RX:");
243 ptr
+= strlen("NET_TX:");
245 for (i
= 0; i
< s
->irqs_len
; ++i
) {
250 while (*ptr
!= ' ' && *ptr
!= 0)
254 s
->irqs_srx
[i
] = atoi(ptr2
);
256 s
->irqs_stx
[i
] = atoi(ptr2
);
259 memset(buff
, 0, sizeof(buff
));
267 static int mem_stats(struct ifstat
*s
)
270 unsigned long total
, free
;
274 FILE *fp
= fopen("/proc/meminfo", "r");
276 whine("Cannot open /proc/meminfo!\n");
280 memset(buff
, 0, sizeof(buff
));
281 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
282 buff
[sizeof(buff
) - 1] = 0;
284 if ((ptr
= strstr(buff
, "MemTotal:")) != NULL
) {
285 ptr
+= strlen("MemTotal:");
291 ret
= sscanf(ptr
, "%lu", &total
);
294 } else if ((ptr
= strstr(buff
, "MemFree:")) != NULL
) {
295 ptr
+= strlen("MemFree:");
301 ret
= sscanf(ptr
, "%lu", &free
);
306 memset(buff
, 0, sizeof(buff
));
310 s
->mem_used
= 100.f
* (total
- free
) / total
;
319 static int sys_stats(struct ifstat
*s
)
325 FILE *fp
= fopen("/proc/stat", "r");
327 whine("Cannot open /proc/stat!\n");
331 stats_check_alloc(s
);
333 memset(buff
, 0, sizeof(buff
));
334 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
335 buff
[sizeof(buff
) - 1] = 0;
337 if ((ptr
= strstr(buff
, "cpu")) != NULL
) {
338 ptr
+= strlen("cpu");
343 while (*ptr
!= ' ' && *ptr
!= 0)
348 if (cpu
< 0 || cpu
>= s
->irqs_len
)
352 ret
= sscanf(ptr
, "%lu%lu%lu%lu%lu", &s
->cpu_user
[cpu
],
353 &s
->cpu_nice
[cpu
], &s
->cpu_sys
[cpu
],
354 &s
->cpu_idle
[cpu
], &s
->cpu_iow
[cpu
]);
357 } else if ((ptr
= strstr(buff
, "ctxt")) != NULL
) {
358 ptr
+= strlen("ctxt");
364 ret
= sscanf(ptr
, "%lu", &s
->ctxt
);
367 } else if ((ptr
= strstr(buff
, "processes")) != NULL
) {
368 ptr
+= strlen("processes");
374 ret
= sscanf(ptr
, "%lu", &s
->forks
);
377 } else if ((ptr
= strstr(buff
, "procs_running")) != NULL
) {
378 ptr
+= strlen("procs_running");
384 ret
= sscanf(ptr
, "%lu", &s
->procs_run
);
387 } else if ((ptr
= strstr(buff
, "procs_blocked")) != NULL
) {
388 ptr
+= strlen("procs_blocked");
394 ret
= sscanf(ptr
, "%lu", &s
->procs_iow
);
399 memset(buff
, 0, sizeof(buff
));
407 static int irq_stats(const char *ifname
, struct ifstat
*s
)
414 if (!strncmp("lo", ifname
, strlen("lo")))
417 FILE *fp
= fopen("/proc/interrupts", "r");
419 whine("Cannot open /proc/interrupts!\n");
423 stats_check_alloc(s
);
425 memset(buff
, 0, sizeof(buff
));
426 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
427 buff
[sizeof(buff
) - 1] = 0;
429 if (strstr(buff
, ifname
) == NULL
)
436 s
->irq_nr
= atoi(buff
);
438 bug_on(s
->irq_nr
== 0);
440 for (i
= 0; i
< s
->irqs_len
; ++i
) {
445 while (*ptr
!= ' ' && *ptr
!= 0)
448 s
->irqs
[i
] = atoi(ptr2
);
451 memset(buff
, 0, sizeof(buff
));
459 static void diff_stats(struct ifstat
*old
, struct ifstat
*new,
464 if(old
->irqs_len
!= new->irqs_len
)
465 return; /* Refetch stats and take old diff! */
467 diff
->rx_bytes
= new->rx_bytes
- old
->rx_bytes
;
468 diff
->rx_packets
= new->rx_packets
- old
->rx_packets
;
469 diff
->rx_drops
= new->rx_drops
- old
->rx_drops
;
470 diff
->rx_errors
= new->rx_errors
- old
->rx_errors
;
471 diff
->rx_fifo
= new->rx_fifo
- old
->rx_fifo
;
472 diff
->rx_frame
= new->rx_frame
- old
->rx_frame
;
473 diff
->rx_multi
= new->rx_multi
- old
->rx_multi
;
474 diff
->tx_bytes
= new->tx_bytes
- old
->tx_bytes
;
475 diff
->tx_packets
= new->tx_packets
- old
->tx_packets
;
476 diff
->tx_drops
= new->tx_drops
- old
->tx_drops
;
477 diff
->tx_errors
= new->tx_errors
- old
->tx_errors
;
478 diff
->tx_fifo
= new->tx_fifo
- old
->tx_fifo
;
479 diff
->tx_colls
= new->tx_colls
- old
->tx_colls
;
480 diff
->tx_carrier
= new->tx_carrier
- old
->tx_carrier
;
481 diff
->wifi_signal_level
= new->wifi_signal_level
- old
->wifi_signal_level
;
482 diff
->wifi_noise_level
= new->wifi_noise_level
- old
->wifi_noise_level
;
483 diff
->wifi_link_qual
= new->wifi_link_qual
- old
->wifi_link_qual
;
484 diff
->ctxt
= new->ctxt
- old
->ctxt
;
485 diff
->forks
= new->forks
- old
->forks
;
486 diff
->procs_run
= new->procs_run
- old
->procs_run
;
487 diff
->procs_iow
= new->procs_iow
- old
->procs_iow
;
489 stats_check_alloc(diff
);
491 diff
->irq_nr
= new->irq_nr
;
493 for (i
= 0; i
< diff
->irqs_len
; ++i
) {
494 diff
->irqs
[i
] = new->irqs
[i
] - old
->irqs
[i
];
495 diff
->irqs_srx
[i
] = new->irqs_srx
[i
] - old
->irqs_srx
[i
];
496 diff
->irqs_stx
[i
] = new->irqs_stx
[i
] - old
->irqs_stx
[i
];
497 diff
->cpu_user
[i
] = new->cpu_user
[i
] - old
->cpu_user
[i
];
498 diff
->cpu_nice
[i
] = new->cpu_nice
[i
] - old
->cpu_nice
[i
];
499 diff
->cpu_sys
[i
] = new->cpu_sys
[i
] - old
->cpu_sys
[i
];
500 diff
->cpu_idle
[i
] = new->cpu_idle
[i
] - old
->cpu_idle
[i
];
501 diff
->cpu_iow
[i
] = new->cpu_iow
[i
] - old
->cpu_iow
[i
];
505 static char *snr_to_str(int level
)
509 return "very good signal";
510 if (level
> 25 && level
<= 40)
511 return "good signal";
512 if (level
> 15 && level
<= 25)
513 return "poor signal";
514 if (level
> 10 && level
<= 15)
515 return "very poor signal";
522 static void screen_init(WINDOW
**screen
)
524 (*screen
) = initscr();
527 nodelay((*screen
), TRUE
);
532 static void screen_update(WINDOW
*screen
, const char *ifname
,
533 struct ifstat
*s
, struct ifstat
*t
,
534 int *first
, double interval
)
539 mvwprintw(screen
, 1, 2, "Kernel net/sys statistics for %s, t=%.2lfs",
542 mvwprintw(screen
, 3, 0,
543 " RX: %16.3f MiB/t %10lu pkts/t %10lu drops/t %10lu errors/t ",
544 1.f
* s
->rx_bytes
/ (1 << 20), s
->rx_packets
, s
->rx_drops
,
546 mvwprintw(screen
, 4, 0,
547 " TX: %16.3f MiB/t %10lu pkts/t %10lu drops/t %10lu errors/t ",
548 1.f
* s
->tx_bytes
/ (1 << 20), s
->tx_packets
, s
->tx_drops
,
551 mvwprintw(screen
, 6, 2,
552 "RX: %16.3f MiB %10lu pkts %10lu drops %10lu errors",
553 1.f
* t
->rx_bytes
/ (1 << 20), t
->rx_packets
, t
->rx_drops
,
555 mvwprintw(screen
, 7, 2,
556 "TX: %16.3f MiB %10lu pkts %10lu drops %10lu errors",
557 1.f
* t
->tx_bytes
/ (1 << 20), t
->tx_packets
, t
->tx_drops
,
560 mvwprintw(screen
, j
++, 2, "SYS: %14ld cs/t %10.1f%% mem "
561 "%13ld running %10ld iowait",
562 s
->ctxt
, t
->mem_used
, t
->procs_run
, t
->procs_iow
);
564 if (s
->irq_nr
!= 0) {
565 for(i
= 0; i
< s
->irqs_len
; ++i
) {
566 unsigned long all
= s
->cpu_user
[i
] + s
->cpu_nice
[i
] +
567 s
->cpu_sys
[i
] + s
->cpu_idle
[i
] +
569 mvwprintw(screen
, j
++, 2, "CPU%d: %13.1f%% usr/t "
570 "%9.1f%% sys/t %10.1f%% idl/t %11.1f%% iow/t ",
572 100.f
* (s
->cpu_user
[i
] + s
->cpu_nice
[i
]) / all
,
573 100.f
* s
->cpu_sys
[i
] / all
,
574 100.f
* s
->cpu_idle
[i
] /all
,
575 100.f
* s
->cpu_iow
[i
] / all
);
578 for(i
= 0; i
< s
->irqs_len
; ++i
)
579 mvwprintw(screen
, j
++, 2, "CPU%d: %14ld irqs/t "
580 "%15ld soirq RX/t %15ld soirq TX/t ",
581 i
, s
->irqs
[i
], s
->irqs_srx
[i
], s
->irqs_stx
[i
]);
583 for(i
= 0; i
< s
->irqs_len
; ++i
)
584 mvwprintw(screen
, j
++, 2, "CPU%d: %14ld irqs",
588 if (t
->wifi_bitrate
> 0) {
589 mvwprintw(screen
, j
++, 2, "LinkQual: %7d/%d (%d/t) ",
590 t
->wifi_link_qual
, t
->wifi_link_qual_max
,
592 mvwprintw(screen
, j
++, 2, "Signal: %8d dBm (%d dBm/t) ",
593 t
->wifi_signal_level
, s
->wifi_signal_level
);
594 mvwprintw(screen
, j
++, 2, "Noise: %8d dBm (%d dBm/t) ",
595 t
->wifi_noise_level
, s
->wifi_noise_level
);
596 mvwprintw(screen
, j
++, 2, "SNR: %8d dBm (%s) ",
597 t
->wifi_signal_level
- t
->wifi_noise_level
,
598 snr_to_str(t
->wifi_signal_level
- t
->wifi_noise_level
));
602 mvwprintw(screen
, 2, 2, "Collecting data ...");
605 mvwprintw(screen
, 2, 2, " ");
611 static void screen_end(void)
616 static void print_update(const char *ifname
, struct ifstat
*s
,
617 struct ifstat
*t
, double interval
)
621 printf("RX: %16.3f MiB/t %10lu Pkts/t %10lu Drops/t %10lu Errors/t\n",
622 1.f
* s
->rx_bytes
/ (1 << 20), s
->rx_packets
, s
->rx_drops
,
624 printf("TX: %16.3f MiB/t %10lu Pkts/t %10lu Drops/t %10lu Errors/t\n",
625 1.f
* s
->tx_bytes
/ (1 << 20), s
->tx_packets
, s
->tx_drops
,
628 for(i
= 0; i
< s
->irqs_len
; ++i
)
629 printf("CPU%d: %10ld IRQs/t "
631 "%10ld SoIRQ TX/t\n", i
,
632 s
->irqs
[i
], s
->irqs_srx
[i
], s
->irqs_stx
[i
]);
633 if (t
->wifi_bitrate
> 0) {
634 printf("LinkQual: %6d/%d (%d/t)\n", t
->wifi_link_qual
,
635 t
->wifi_link_qual_max
, s
->wifi_link_qual
);
636 printf("Signal: %8d dBm (%d dBm/t)\n", t
->wifi_signal_level
,
637 s
->wifi_signal_level
);
638 printf("Noise: %8d dBm (%d dBm/t)\n", t
->wifi_noise_level
,
639 s
->wifi_noise_level
);
643 static void print_update_csv(const char *ifname
, struct ifstat
*s
,
644 struct ifstat
*t
, double interval
)
648 printf("%ld,%lu,%lu,%lu,%lu,", time(0), s
->rx_bytes
, s
->rx_packets
,
649 s
->rx_drops
, s
->rx_errors
);
650 printf("%lu,%lu,%lu,%lu", s
->tx_bytes
, s
->tx_packets
, s
->tx_drops
,
653 for(i
= 0; i
< s
->irqs_len
; ++i
)
654 printf(",%ld,%ld,%ld", s
->irqs
[i
], s
->irqs_srx
[i
],
656 if (t
->wifi_bitrate
> 0) {
657 printf(",%d,%d", t
->wifi_link_qual
, t
->wifi_link_qual_max
);
658 printf(",%d", t
->wifi_signal_level
);
659 printf(",%d", t
->wifi_noise_level
);
664 static void print_update_csv_hdr(const char *ifname
, struct ifstat
*s
,
665 struct ifstat
*t
, double interval
)
669 printf("Unixtime,RX Byte/t,RX Pkts/t,RX Drops/t,RX Errors/t,");
670 printf("TX Byte/t,TX Pkts/t,TX Drops/t,TX Errors/t");
672 for(i
= 0; i
< s
->irqs_len
; ++i
)
673 printf(",CPU%d IRQs/t,CPU%d SoIRQ RX/t,"
674 "CPU%d SoIRQ TX/t", i
, i
, i
);
675 if (t
->wifi_bitrate
> 0)
676 printf(",LinkQual,LinkQualMax,Signal Level,Noise Level");
680 static inline int do_stats(const char *ifname
, struct ifstat
*s
)
684 ret
+= rxtx_stats(ifname
, s
);
685 ret
+= irq_stats(ifname
, s
);
686 ret
+= irq_sstats(s
);
689 ret
+= wifi_stats(ifname
, s
);
694 static int screen_loop(const char *ifname
, uint32_t interval
)
696 int ret
= 0, first
= 1;
697 struct ifstat old
, new, curr
;
698 WINDOW
*screen
= NULL
;
700 memset(&old
, 0, sizeof(old
));
701 memset(&new, 0, sizeof(new));
702 memset(&curr
, 0, sizeof(curr
));
704 screen_init(&screen
);
710 screen_update(screen
, ifname
, &curr
, &new, &first
, interval
);
712 ret
= do_stats(ifname
, &old
);
718 ret
= do_stats(ifname
, &new);
722 diff_stats(&old
, &new, &curr
);
728 whine("Error fetching stats!\n");
739 static int print_loop(const char *ifname
, uint32_t interval
)
742 struct ifstat old
, new, curr
;
744 memset(&old
, 0, sizeof(old
));
745 memset(&new, 0, sizeof(new));
746 memset(&curr
, 0, sizeof(curr
));
748 ret
= do_stats(ifname
, &old
);
754 ret
= do_stats(ifname
, &new);
758 diff_stats(&old
, &new, &curr
);
760 if (first
&& (mode
& TERM_MODE_CSV_HDR
) ==
762 print_update_csv_hdr(ifname
, &curr
, &new, interval
);
766 if ((mode
& TERM_MODE_CSV
) == TERM_MODE_CSV
)
767 print_update_csv(ifname
, &curr
, &new, interval
);
768 else if ((mode
& TERM_MODE_NORMAL
) == TERM_MODE_NORMAL
)
769 print_update(ifname
, &curr
, &new, interval
);
770 } while (loop
&& !sigint
);
773 whine("Error fetching stats!\n");
784 static void help(void)
786 printf("\n%s %s, top-like kernel networking and system statistics\n",
787 PROGNAME_STRING
, VERSION_STRING
);
788 puts("http://www.netsniff-ng.org\n\n"
789 "Usage: ifpps [options] || ifpps <netdev>\n"
791 " -d|--dev <netdev> Device to fetch statistics for i.e., eth0\n"
792 " -p|--promisc Promiscuous mode\n"
793 " -t|--interval <time> Refresh time in sec (default 1 s)\n"
794 " -c|--term Output to terminal\n"
795 " -C|--csv Output to terminal as CSV\n"
796 " E.g. post-processing with Gnuplot et al.\n"
797 " -H|--csv-tablehead Print CSV table head\n"
798 " -l|--loop Loop terminal output\n"
799 " -v|--version Print version\n"
800 " -h|--help Print this help\n\n"
802 " ifpps --dev eth0\n"
803 " ifpps --dev eth0 --interval 60 --csv\n\n"
804 "Please report bugs to <bugs@netsniff-ng.org>\n"
805 "Copyright (C) 2009-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n"
806 "License: GNU GPL version 2.0\n"
807 "This is free software: you are free to change and redistribute it.\n"
808 "There is NO WARRANTY, to the extent permitted by law.\n");
812 static void version(void)
814 printf("\n%s %s, top-like kernel networking statistics per sec\n",
815 PROGNAME_STRING
, VERSION_STRING
);
816 puts("http://www.netsniff-ng.org\n\n"
817 "Please report bugs to <bugs@netsniff-ng.org>\n"
818 "Copyright (C) 2009-2012 Daniel Borkmann <daniel@netsniff-ng.org>\n"
819 "License: GNU GPL version 2.0\n"
820 "This is free software: you are free to change and redistribute it.\n"
821 "There is NO WARRANTY, to the extent permitted by law.\n");
825 int main(int argc
, char **argv
)
828 int c
, opt_index
, ret
;
829 unsigned int promisc
= 0;
831 uint32_t interval
= 1;
832 int (*main_loop
)(const char *ifname
, uint32_t interval
) = screen_loop
;
834 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
835 &opt_index
)) != EOF
) {
844 ifname
= xstrndup(optarg
, IFNAMSIZ
);
847 interval
= atoi(optarg
);
850 mode
|= TERM_MODE_NORMAL
;
851 main_loop
= print_loop
;
860 mode
|= TERM_MODE_CSV
;
861 main_loop
= print_loop
;
864 mode
|= TERM_MODE_CSV_HDR
;
865 main_loop
= print_loop
;
871 panic("Option -%c requires an argument!\n",
875 whine("Unknown option character "
876 "`0x%X\'!\n", optopt
);
887 ifname
= xstrndup(argv
[1], IFNAMSIZ
);
889 panic("No networking device given!\n");
890 if (!strncmp("lo", ifname
, IFNAMSIZ
))
891 panic("lo is not supported!\n");
892 if (device_mtu(ifname
) == 0)
893 panic("This is no networking device!\n");
894 register_signal(SIGINT
, signal_handler
);
895 register_signal(SIGHUP
, signal_handler
);
897 check_for_root_maybe_die();
898 ifflags
= enter_promiscuous_mode(ifname
);
900 ret
= main_loop(ifname
, interval
);
902 leave_promiscuous_mode(ifname
, ifflags
);