diff options
author | Guy Harris <guy@alum.mit.edu> | 2015-06-04 00:09:10 -0700 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2015-06-04 00:09:10 -0700 |
commit | 85c3887483bd14c1f2748ac891bb1b19d2f0c877 (patch) | |
tree | 8eb666279612be7c98e43251f2f7afba7659066b /pcap-linux.c | |
parent | cd03c8fd9fe7a0c42d043f9c6ad7c5dcb6515929 (diff) |
Don't timeout poll() with TPACKET_V3 in 3.19 and later.
We don't need to do the workaround for not getting wakeups when buffers
are handed to us, nor do we have to do a timeout in poll() for the
benefit of programs that expect the timeout to expire even if no packets
have arrived, so, with TPACKET_V3 in 3.19 and later, we always use a
timeout of -1 for poll().
This eliminates some spurious wakeups from poll(), due to the poll()
call *itself* timing out, that turn into spurious timeouts; see GitHub
issue #383.
Diffstat (limited to 'pcap-linux.c')
-rw-r--r-- | pcap-linux.c | 80 |
1 files changed, 62 insertions, 18 deletions
diff --git a/pcap-linux.c b/pcap-linux.c index b19e4a1a..e08f0b12 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -1300,33 +1300,77 @@ static void pcap_cleanup_linux( pcap_t *handle ) static void set_poll_timeout(struct pcap_linux *handlep) { +#ifdef HAVE_TPACKET3 + struct utsname utsname; + char *version_component, *endp; + int major, minor; + int broken_tpacket_v3 = 1; + + /* + * Some versions of TPACKET_V3 have annoying bugs/misfeatures + * around which we have to work. Determine if we have those + * problems or not. + */ + if (uname(&utsname) == 0) { + /* + * 3.19 is the first release with a fixed version of + * TPACKET_V3. We treat anything before that as + * not haveing a fixed version; that may really mean + * it has *no* version. + */ + version_component = utsname.release; + major = strtol(version_component, &endp, 10); + if (endp != version_component && *endp == '.') { + /* + * OK, that was a valid major version. + * Get the minor version. + */ + version_component = endp + 1; + minor = strtol(version_component, &endp, 10); + if (endp != version_component && + (*endp == '.' || *endp == '\0')) { + /* + * OK, that was a valid minor version. + * Is this 3.19 or newer? + */ + if (major >= 4 || (major == 3 && minor >= 19)) { + /* Yes. TPACKET_V3 works correctly. */ + broken_tpacket_v3 = 0; + } + } + } + } +#endif if (handlep->timeout == 0) { #ifdef HAVE_TPACKET3 /* - * XXX - due to a set of (mis)features in the - * TPACKET_V3 kernel code, blocking forever with - * a TPACKET_V3 socket can, if few packets - * are arriving and passing the socket filter, - * cause most packets to be dropped. See - * libpcap issue #335 for the full painful - * story. The workaround is to have poll() - * time out very quickly, so we grab the - * frames handed to us, and return them to - * the kernel, ASAP. + * XXX - due to a set of (mis)features in the TPACKET_V3 + * kernel code prior to the 3.19 kernel, blocking forever + * with a TPACKET_V3 socket can, if few packets are + * arriving and passing the socket filter, cause most + * packets to be dropped. See libpcap issue #335 for the + * full painful story. * - * If those issues are ever fixed, we might - * want to check the kernel version and block - * forever with TPACKET_V3 if we're running - * with a kernel that has the fix. + * The workaround is to have poll() time out very quickly, + * so we grab the frames handed to us, and return them to + * the kernel, ASAP. */ - if (handlep->tp_version == TPACKET_V3) + if (handlep->tp_version == TPACKET_V3 && broken_tpacket_v3) handlep->poll_timeout = 1; /* don't block for very long */ else #endif handlep->poll_timeout = -1; /* block forever */ - } else if (handlep->timeout > 0) - handlep->poll_timeout = handlep->timeout; /* block for that amount of time */ - else + } else if (handlep->timeout > 0) { + /* + * For TPACKET_V3, the timeout is handled by the kernel, + * so block forever; that way, we don't get extra timeouts. + * Don't do that if we have a broken TPACKET_V3, though. + */ + if (handlep->tp_version == TPACKET_V3 && !broken_tpacket_v3) + handlep->poll_timeout = -1; /* block forever, let TPACKET_V3 wake us up */ + else + handlep->poll_timeout = handlep->timeout; /* block for that amount of time */ + } else handlep->poll_timeout = 0; /* non-blocking mode - poll to pick up errors */ } |