tcpdump mailing list archives

Re: TPACKET v3 / pcap_open_live - backwards compatibility for projects


From: Guy Harris <guy () alum mit edu>
Date: Thu, 27 Mar 2014 15:15:56 -0700


On Mar 27, 2014, at 1:50 PM, John Farnsworth <John.Farnsworth () imc-chicago com> wrote:

If your application is expecting a low rate of packet delivery and needs to see packets as soon as they arrive, it 
should simply call pcap_set_immediate_mode() if it is available, regardless of what operating system it's running on 
or what version of libpcap it's using (as long as that version *has* pcap_set_immediate_mode()); "show me packets as 
soon as they arrive" is *exactly* what "immediate mode" means.  (On systems with BPF, it turns on BPF's "immediate 
mode" - the name for it in libpcap was taken from BPF! - which disables the buffering and timeout.)

This is where my problem lives:  if you use an older version of libpcap such as many Linux distributions still 
provide, you will get the behavior using pcap_open_live equivalent to immediate mode.

Perhaps better phrased as "you happen to get behavior equivalent to immediate mode"; this isn't by design, it's by lack 
of a timeout-based buffering mechanism in TPACKET_V2, TPACKET_V1, and the pre-turbopacket "read a packet at a time with 
recvmsg()" kernel code paths.

At least as far back as libpcap 0.7, the pcap man page said:

        The read timeout is used to arrange that the read not necessarily return immediately when a packet is seen, but 
that it wait for some amount of time to allow more packets to arrive and to read multiple packets from the OS kernel in 
one operation.  Not all platforms support a read timeout; on platforms that don't, the read timeout is ignored.

which indicates that there's no guarantee of immediate packet delivery - and no explicit claim that some *particular* 
platforms provide immediate packet delivery in all cases.

However, I don't see a method to place logic into code to invoke pcap_set_immediate_mode only if it exists, as I 
can't trust it to exist, since it is new.  Yet I must specify it to retain legacy behavior.  This puts me in an odd 
dependency loop that I must make I suppose 2 versions of the application, one against libpcap 1.5 and one against 
libpcap 1.2 and expect the newer one to fail to compile against the older lib.

Another alternative, if your app is linked dynamically with libpcap, is to try using dlopen() to load libpcap.so (I 
*think* the glibc dynamic loader is smart enough to recognize that the library is already loaded, and just give you a 
handle for it), use dlsym() to find a pointer to pcap_set_immediate_mode(), and, if the pointer is found, call through 
that pointer with the appropriate arguments.  (This is a technique commonly used on Windows with its equivalent APIs, 
LoadLibrary()/GetModuleHandle() and GetProcAddress(), to handle APIs present in some OS versions but not others, and 
was also used on Linux, with libpcap, in Wireshark at one point.)

I was hoping there was some sort of API version that I could identify using a #ifdef to macro out the code rather 
than doing ugly things like autoconf external version identification, but I couldn't find it, just the 
pcap_lib_version, which doesn't help for that situation.

Whether using compile-time version-number #ifdefs is less ugly than using autoconf is a matter of opinion. :-)  The 
autoconf developers, not surprisingly :-), would suggest using autoconf, as what you *really* want to know is "does 
this version of libpcap support pcap_set_immediate_mode()", not "what version of libpcap is this" - determining the 
libpcap version is just a way to discover whether it has pcap_set_immediate_mode().

I realize this behavior is not guaranteed cross-platform, and that there are very much 2 different expectations for 
the result of the pcap_loop.

One should not expect immediate delivery on *any* platform unless the code calls pcap_set_immediate_mode(); one should, 
however, expect delivery within N milliseconds if a timeout of N was specified in pcap_open_live(), or was specified 
pcap_set_timeout() before calling pcap_activate().

In my case, I'm looking for pcap_loop to trigger without a delay as soon as a packet is available - and this is the 
behavior that existed in previous versions

...*on Linux* (and some other platforms, such as IRIX).  It was *not* the behavior that existed in *BSD or OS X or 
Solaris, for example; those platforms have *always* buffered packets and delivered them only if the buffer filled or 
the timeout expired.

I don't suggest this to be a bug - it's not, it's just a change in default behavior from before which has some pretty 
significant impact.

...on applications that implicitly depended on a quirk of the implementation.

_______________________________________________
tcpdump-workers mailing list
tcpdump-workers () lists tcpdump org
https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers


Current thread: