On Mar 27, 2014, at 1:50 PM, John Farnsworth <john.farnswo...@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

Reply via email to