tcpdump mailing list archives

Linux pcap_stats ignore kernel stats even when they are available


From: Alexander Dupuy <dupuy () cs columbia edu>
Date: Wed, 22 Feb 2006 17:48:56 -0500

[I tried sending this back on February 4 and 6, but there were problems with the list, and I don't believe it ever made it through. My apologies if this is a duplicate.]

The recent changes to pcap-linux.c to prevent double-counting of
received packets have an unfortunate bug that causes the kernel
statistics to always be ignored, even if they are available.  Instead,
the accurate count of packets processed by libpcap is used as the
receive count (although it doesn't count packets received by the kernel
but not yet processed by the application) and the drop count is always zero.

The crux of the problem is that the line with

        *stats = handle->md.stat;

was replaced with

        stats->ps_recv = handle->md.packets_read;
        stats->ps_drop = 0;

which ignores the recv and drop data in handle->md.stat that was just
updated from the kernel information above.

I've attached a patch that fixes this problem, and also moves some
comments around a bit so that it is clearer what is going on.

@alex


Index: pcap-linux.c
===================================================================
RCS file: /tcpdump/master/libpcap/pcap-linux.c,v
retrieving revision 1.119
diff -u -r1.119 pcap-linux.c
--- pcap-linux.c        22 Jan 2006 20:11:26 -0000      1.119
+++ pcap-linux.c        4 Feb 2006 16:09:11 -0000
@@ -782,6 +782,37 @@
        socklen_t len = sizeof (struct tpacket_stats);
 #endif
 
+       /*
+        * On systems where the PACKET_STATISTICS "getsockopt()" argument
+        * is supported on PF_PACKET sockets:
+        *
+        *      "ps_recv" counts only packets that *passed* the filter,
+        *      not packets that didn't pass the filter.  This includes
+        *      packets later dropped because we ran out of buffer space.
+        *
+        *      "ps_drop" counts packets dropped because we ran out of
+        *      buffer space.  It doesn't count packets dropped by the
+        *      interface driver.  It counts only packets that passed
+        *      the filter.
+        *
+        *      Both statistics include packets not yet read from the
+        *      kernel by libpcap, and thus not yet seen by the application.
+        *
+        * On systems where the PACKET_STATISTICS "getsockopt()" argument
+        * is not supported on PF_PACKET sockets:
+        *
+        *      "ps_recv" counts only packets that *passed* the filter,
+        *      not packets that didn't pass the filter.  It does not
+        *      count packets dropped because we ran out of buffer
+        *      space.
+        *
+        *      "ps_drop" is not supported.
+        *
+        *      "ps_recv" doesn't include packets not yet read from
+        *      the kernel by libpcap.
+        *
+        */
+
 #ifdef HAVE_TPACKET_STATS
        /*
         * Try to get the packet counts from the kernel.
@@ -819,58 +850,32 @@
                handle->md.stat.ps_recv += kstats.tp_packets;
                handle->md.stat.ps_drop += kstats.tp_drops;
        }
-       else
+       else if (errno != EOPNOTSUPP)
        {
-               /*
-                * If the error was EOPNOTSUPP, fall through, so that
-                * if you build the library on a system with
-                * "struct tpacket_stats" and run it on a system
-                * that doesn't, it works as it does if the library
-                * is built on a system without "struct tpacket_stats".
-                */
-               if (errno != EOPNOTSUPP) {
-                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
-                           "pcap_stats: %s", pcap_strerror(errno));
-                       return -1;
-               }
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                   "pcap_stats: %s", pcap_strerror(errno));
+               return -1;
        }
+       /*
+        * If the error was EOPNOTSUPP, fall through, so that
+        * if you build the library on a system with
+        * "struct tpacket_stats" and run it on a system
+        * that doesn't, it works as it does if the library
+        * is built on a system without "struct tpacket_stats".
+        */
+       else
 #endif
        /*
-        * On systems where the PACKET_STATISTICS "getsockopt()" argument
-        * is supported on PF_PACKET sockets:
-        *
-        *      "ps_recv" counts only packets that *passed* the filter,
-        *      not packets that didn't pass the filter.  This includes
-        *      packets later dropped because we ran out of buffer space.
-        *
-        *      "ps_drop" counts packets dropped because we ran out of
-        *      buffer space.  It doesn't count packets dropped by the
-        *      interface driver.  It counts only packets that passed
-        *      the filter.
-        *
-        *      Both statistics include packets not yet read from the
-        *      kernel by libpcap, and thus not yet seen by the application.
-        *
-        * On systems where the PACKET_STATISTICS "getsockopt()" argument
-        * is not supported on PF_PACKET sockets:
-        *
-        *      "ps_recv" counts only packets that *passed* the filter,
-        *      not packets that didn't pass the filter.  It does not
-        *      count packets dropped because we ran out of buffer
-        *      space.
-        *
-        *      "ps_drop" is not supported.
-        *
-        *      "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.
         */
-       stats->ps_recv = handle->md.packets_read;
-       stats->ps_drop = 0;
+       {
+               handle->md.stat.ps_recv = handle->md.packets_read;
+               handle->md.stat.ps_drop = 0;
+       }
+       *stats = handle->md.stat;
        return 0;
 }
 


-
This is the tcpdump-workers list.
Visit https://lists.sandelman.ca/ to unsubscribe.

Current thread: