From Dustin Spicuzza: support ps_ifdrop on Linux, using /proc/net/dev.
Fix the title of the pcap_stats man page, and give more detail - and a lot of caveats.
This commit is contained in:
parent
8b04d928b6
commit
2032d35228
|
@ -139,6 +139,7 @@ struct pcap_md {
|
||||||
u_int tp_version; /* version of tpacket_hdr for mmaped ring */
|
u_int tp_version; /* version of tpacket_hdr for mmaped ring */
|
||||||
u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */
|
u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */
|
||||||
u_char *oneshot_buffer; /* buffer for copy of packet */
|
u_char *oneshot_buffer; /* buffer for copy of packet */
|
||||||
|
long proc_dropped; /* packets reported dropped by /proc/net/dev */
|
||||||
#endif /* linux */
|
#endif /* linux */
|
||||||
|
|
||||||
#ifdef HAVE_DAG_API
|
#ifdef HAVE_DAG_API
|
||||||
|
|
84
pcap-linux.c
84
pcap-linux.c
|
@ -890,6 +890,60 @@ pcap_can_set_rfmon_linux(pcap_t *handle)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* grabs the number of dropped packets by the interface from /proc/net/dev */
|
||||||
|
static long int
|
||||||
|
linux_if_drops(const char * if_name)
|
||||||
|
{
|
||||||
|
char buffer[512];
|
||||||
|
char * bufptr;
|
||||||
|
FILE * file;
|
||||||
|
int field_to_convert = 3, if_name_sz = strlen(if_name);
|
||||||
|
long int dropped_pkts = 0;
|
||||||
|
|
||||||
|
file = fopen("/proc/net/dev", "r");
|
||||||
|
if (!file)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (!dropped_pkts && fgets( buffer, sizeof(buffer), file ))
|
||||||
|
{
|
||||||
|
/* search for 'bytes' -- if its in there, then
|
||||||
|
that means we need to grab the fourth field. otherwise
|
||||||
|
grab the third field. */
|
||||||
|
if (field_to_convert != 4 && strstr(buffer, "bytes"))
|
||||||
|
{
|
||||||
|
field_to_convert = 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find iface and make sure it actually matches -- space before the name and : after it */
|
||||||
|
if ((bufptr = strstr(buffer, if_name)) &&
|
||||||
|
(bufptr == buffer || *(bufptr-1) == ' ') &&
|
||||||
|
*(bufptr + if_name_sz) == ':')
|
||||||
|
{
|
||||||
|
bufptr = bufptr + if_name_sz + 1;
|
||||||
|
|
||||||
|
/* grab the nth field from it */
|
||||||
|
while( --field_to_convert && *bufptr != '\0')
|
||||||
|
{
|
||||||
|
while (*bufptr != '\0' && *(bufptr++) == ' ');
|
||||||
|
while (*bufptr != '\0' && *(bufptr++) != ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get rid of any final spaces */
|
||||||
|
while (*bufptr != '\0' && *bufptr == ' ') bufptr++;
|
||||||
|
|
||||||
|
if (*bufptr != '\0')
|
||||||
|
dropped_pkts = strtol(bufptr, NULL, 10);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return dropped_pkts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With older kernels promiscuous mode is kind of interesting because we
|
* With older kernels promiscuous mode is kind of interesting because we
|
||||||
* have to reset the interface before exiting. The problem can't really
|
* have to reset the interface before exiting. The problem can't really
|
||||||
|
@ -1065,6 +1119,14 @@ pcap_activate_linux(pcap_t *handle)
|
||||||
pcap_strerror(errno) );
|
pcap_strerror(errno) );
|
||||||
return PCAP_ERROR;
|
return PCAP_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're in promiscuous mode, then we probably want
|
||||||
|
* to see when the interface drops packets too, so get an
|
||||||
|
* initial count from /proc/net/dev
|
||||||
|
*/
|
||||||
|
if (handle->opt.promisc)
|
||||||
|
handle->md.proc_dropped = linux_if_drops(handle->md.device);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Current Linux kernels use the protocol family PF_PACKET to
|
* Current Linux kernels use the protocol family PF_PACKET to
|
||||||
|
@ -1563,6 +1625,18 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
|
||||||
socklen_t len = sizeof (struct tpacket_stats);
|
socklen_t len = sizeof (struct tpacket_stats);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
long if_dropped = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To fill in ps_ifdrop, we parse /proc/net/dev for the number
|
||||||
|
*/
|
||||||
|
if (handle->opt.promisc)
|
||||||
|
{
|
||||||
|
if_dropped = handle->md.proc_dropped;
|
||||||
|
handle->md.proc_dropped = linux_if_drops(handle->md.device);
|
||||||
|
handle->md.stat.ps_ifdrop += (handle->md.proc_dropped - if_dropped);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_TPACKET_STATS
|
#ifdef HAVE_TPACKET_STATS
|
||||||
/*
|
/*
|
||||||
* Try to get the packet counts from the kernel.
|
* Try to get the packet counts from the kernel.
|
||||||
|
@ -1583,6 +1657,8 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
|
||||||
* dropped by the interface driver. It counts only
|
* dropped by the interface driver. It counts only
|
||||||
* packets that passed the filter.
|
* packets that passed the filter.
|
||||||
*
|
*
|
||||||
|
* See above for ps_ifdrop.
|
||||||
|
*
|
||||||
* Both statistics include packets not yet read from
|
* Both statistics include packets not yet read from
|
||||||
* the kernel by libpcap, and thus not yet seen by
|
* the kernel by libpcap, and thus not yet seen by
|
||||||
* the application.
|
* the application.
|
||||||
|
@ -1646,16 +1722,22 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
|
||||||
*
|
*
|
||||||
* "ps_drop" is not supported.
|
* "ps_drop" is not supported.
|
||||||
*
|
*
|
||||||
|
* "ps_ifdrop" is supported. It will return the number
|
||||||
|
* of drops the interface reports in /proc/net/dev
|
||||||
|
*
|
||||||
* "ps_recv" doesn't include packets not yet read from
|
* "ps_recv" doesn't include packets not yet read from
|
||||||
* the kernel by libpcap.
|
* the kernel by libpcap.
|
||||||
*
|
*
|
||||||
* We maintain the count of packets processed by libpcap in
|
* We maintain the count of packets processed by libpcap in
|
||||||
* "md.packets_read", for reasons described in the comment
|
* "md.packets_read", for reasons described in the comment
|
||||||
* at the end of pcap_read_packet(). We have no idea how many
|
* at the end of pcap_read_packet(). We have no idea how many
|
||||||
* packets were dropped.
|
* packets were dropped by the kernel buffers -- but we know
|
||||||
|
* how many the interface dropped, so we can return that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
stats->ps_recv = handle->md.packets_read;
|
stats->ps_recv = handle->md.packets_read;
|
||||||
stats->ps_drop = 0;
|
stats->ps_drop = 0;
|
||||||
|
stats->ps_ifdrop = handle->md.stat.ps_drop;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ struct pcap_pkthdr {
|
||||||
struct pcap_stat {
|
struct pcap_stat {
|
||||||
u_int ps_recv; /* number of packets received */
|
u_int ps_recv; /* number of packets received */
|
||||||
u_int ps_drop; /* number of packets dropped */
|
u_int ps_drop; /* number of packets dropped */
|
||||||
u_int ps_ifdrop; /* drops by interface XXX not yet supported */
|
u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
u_int bs_capt; /* number of packets that reach the application */
|
u_int bs_capt; /* number of packets that reach the application */
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
.\"
|
.\"
|
||||||
.TH PCAP_SNAPSHOT 3PCAP "5 April 2008"
|
.TH PCAP_STATS 3PCAP "7 September 2009"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pcap_stats \- get capture statistics
|
pcap_stats \- get capture statistics
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -35,17 +35,57 @@ int pcap_stats(pcap_t *p, struct pcap_stat *ps);
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.B pcap_stats()
|
.B pcap_stats()
|
||||||
fills in the
|
fills in the
|
||||||
.I pcap_stat
|
.B struct pcap_stat
|
||||||
structure pointed to by its second argument. The values represent
|
pointed to by its second argument. The values represent
|
||||||
packet statistics from the start of the run to the time of the call.
|
packet statistics from the start of the run to the time of the call.
|
||||||
.PP
|
.PP
|
||||||
.B pcap_stats()
|
.B pcap_stats()
|
||||||
is supported only on live captures, not on ``savefiles''; no statistics
|
is supported only on live captures, not on ``savefiles''; no statistics
|
||||||
are stored in ``savefiles'', so no statistics are available when reading
|
are stored in ``savefiles'', so no statistics are available when reading
|
||||||
from a ``savefile''.
|
from a ``savefile''.
|
||||||
|
.PP
|
||||||
|
A
|
||||||
|
.B struct pcap_stat
|
||||||
|
has the following members:
|
||||||
|
.RS
|
||||||
|
.TP
|
||||||
|
.B ps_recv
|
||||||
|
number of packets received;
|
||||||
|
.TP
|
||||||
|
.B ps_drop
|
||||||
|
number of packets dropped because there was no room in the operating
|
||||||
|
system's buffer when they arrived, because packets weren't being read
|
||||||
|
fast enough;
|
||||||
|
.TP
|
||||||
|
.B ps_ifdrop
|
||||||
|
number of packets dropped by the network interface or its driver.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
The statistics do not behave the same way on all platforms.
|
||||||
|
.B ps_recv
|
||||||
|
might count packets whether they passed any filter set with
|
||||||
|
.BR pcap_setfilter (3PCAP)
|
||||||
|
or not, or it might count only packets that pass the filter.
|
||||||
|
It also might, or might not, count packets dropped because there was no
|
||||||
|
room in the operating system's buffer when they arrived.
|
||||||
|
.B ps_drop
|
||||||
|
is not available on all platforms; it is zero on platforms where it's
|
||||||
|
not available. If packet filtering is done in libpcap, rather than in
|
||||||
|
the operating system, it would count packets that don't pass the filter.
|
||||||
|
Both
|
||||||
|
.B ps_recv
|
||||||
|
and
|
||||||
|
.B ps_drop
|
||||||
|
might, or might not, count packets not yet read from the operating
|
||||||
|
system and thus not yet seen by the application.
|
||||||
|
.B ps_ifdrop
|
||||||
|
might, or might not, be implemented; if it's zero, that might mean that
|
||||||
|
no packets were dropped by the interface, or it might mean that the
|
||||||
|
statistic is unavailable, so it should not be treated as an indication
|
||||||
|
that the interface did not drop any packets.
|
||||||
.SH RETURN VALUE
|
.SH RETURN VALUE
|
||||||
.B pcap_stats()
|
.B pcap_stats()
|
||||||
returns 0 on success and returns \-1 if there is an error or the
|
returns 0 on success and returns \-1 if there is an error or if
|
||||||
.I p
|
.I p
|
||||||
doesn't support packet statistics.
|
doesn't support packet statistics.
|
||||||
If \-1 is returned,
|
If \-1 is returned,
|
||||||
|
|
Reference in New Issue