dect
/
libpcap
Archived
13
0
Fork 0

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:
Guy Harris 2009-09-07 16:23:15 -07:00
parent 8b04d928b6
commit 2032d35228
4 changed files with 129 additions and 6 deletions

View File

@ -139,6 +139,7 @@ struct pcap_md {
u_int tp_version; /* version 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 */
long proc_dropped; /* packets reported dropped by /proc/net/dev */
#endif /* linux */
#ifdef HAVE_DAG_API

View File

@ -890,6 +890,60 @@ pcap_can_set_rfmon_linux(pcap_t *handle)
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
* have to reset the interface before exiting. The problem can't really
@ -1066,6 +1120,14 @@ pcap_activate_linux(pcap_t *handle)
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
* allow direct access to all packets on the network while
@ -1563,6 +1625,18 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
socklen_t len = sizeof (struct tpacket_stats);
#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
/*
* 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
* packets that passed the filter.
*
* See above for ps_ifdrop.
*
* Both statistics include packets not yet read from
* the kernel by libpcap, and thus not yet seen by
* the application.
@ -1646,16 +1722,22 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
*
* "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
* the kernel by libpcap.
*
* We maintain the count of packets processed by libpcap in
* "md.packets_read", for reasons described in the comment
* 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_drop = 0;
stats->ps_ifdrop = handle->md.stat.ps_drop;
return 0;
}

View File

@ -163,7 +163,7 @@ struct pcap_pkthdr {
struct pcap_stat {
u_int ps_recv; /* number of packets received */
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
u_int bs_capt; /* number of packets that reach the application */
#endif /* WIN32 */

View File

@ -19,7 +19,7 @@
.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
.TH PCAP_SNAPSHOT 3PCAP "5 April 2008"
.TH PCAP_STATS 3PCAP "7 September 2009"
.SH NAME
pcap_stats \- get capture statistics
.SH SYNOPSIS
@ -35,17 +35,57 @@ int pcap_stats(pcap_t *p, struct pcap_stat *ps);
.SH DESCRIPTION
.B pcap_stats()
fills in the
.I pcap_stat
structure pointed to by its second argument. The values represent
.B struct pcap_stat
pointed to by its second argument. The values represent
packet statistics from the start of the run to the time of the call.
.PP
.B pcap_stats()
is supported only on live captures, not on ``savefiles''; no statistics
are stored in ``savefiles'', so no statistics are available when reading
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
.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
doesn't support packet statistics.
If \-1 is returned,