Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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.
  • Loading branch information...
commit 2032d3522861c8dcf335546b10ffa6f51f3c2497 1 parent 8b04d92
@guyharris guyharris authored
Showing with 129 additions and 6 deletions.
  1. +1 −0  pcap-int.h
  2. +83 −1 pcap-linux.c
  3. +1 −1  pcap/pcap.h
  4. +44 −4 pcap_stats.3pcap
View
1  pcap-int.h
@@ -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
84 pcap-linux.c
@@ -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
@@ -1065,6 +1119,14 @@ pcap_activate_linux(pcap_t *handle)
pcap_strerror(errno) );
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
@@ -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
2  pcap/pcap.h
@@ -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
48 pcap_stats.3pcap
@@ -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,
Please sign in to comment.
Something went wrong with that request. Please try again.