Stephen Donnelly wrote:
> Dustin Spicuzza wrote:
> 
>>> So after reading the libpcap and kernel source, I see that this is
>>> actually how its supposed to work. But it *seems* like it would be quite
>>> nice if we could grab the interface driver drop statistics as well as
>>> drops resulting from the capture buffer filling up.
>>>
>>> I'm looking for a way to query the kernel about this number -- should I
>>> bother submitting a patch if I can get it, or is the current behavior
>>> more desired?
>>
>> It appears that the only way to get this number is by looking at
>> /proc/stats/dev, so I added something that can parse it for the correct
>> interface, and get the drop stats from there. Since those are cumulative
>> over the boot time of the system, it stores a number and does
>> incremental updates of the number. It doesn't do this when not in
>> promiscuous mode however, since that doesn't make any sense.
>>
>> It works for me, let me know what you think.
> 
> The current 'drop' count in libpcap is not intuitive, and frequently
> arguably undercounts since it does not include 'rx buffer overflow' and
> similar interface/OS specific packet loss. OTOH, the documentation is
> quite clear about what it does count I think.

No, its not; its actually quite vague. From the man page:

"pcap_stats() fills in the pcap_stat structure pointed to by its second
argument.  The values represent packet statistics from the start of the
run to the time of the call."

The code has a few comments as to what it counts, and *that* is quite
clear. However, I would imagine not too many people will read that
unless they're using pcap from source.

And, after looking at it, there *is* support for drops by the interface
in pcap_stat(), its just currently not used by very many platforms. I
didn't see this previously, but looking at pcap.h:

/*
 * As returned by the pcap_stats()
 */
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 */
#ifdef WIN32
        u_int bs_capt;          /* number of packets that reach the
application */
#endif /* WIN32 */
};


So... I've changed my patch to populate ps_ifdrop instead, and it should
be good to go, without screwing with current applications. I suppose the
man page should be updated to mention that ps_ifdrop is only supported
on a few platforms (I noticed that grep shows one or two instances where
it is used).

Dustin






-- 
Innovation is just a problem away
diff --git a/pcap-int.h b/pcap-int.h
index a548220..5786ea5 100644
--- a/pcap-int.h
+++ b/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
diff --git a/pcap-linux.c b/pcap-linux.c
index 25208f6..c529d56 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -891,6 +891,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)
                         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
@@ -1564,6 +1626,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.
@@ -1584,6 +1658,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.
@@ -1647,16 +1723,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;
 }
 
diff --git a/pcap/pcap.h b/pcap/pcap.h
index 94fb722..5886c49 100644
--- a/pcap/pcap.h
+++ b/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 */

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to