aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <gharris@ubu9-10.(none)>2011-05-20 10:54:30 -0700
committerGuy Harris <gharris@ubu9-10.(none)>2011-05-20 10:54:30 -0700
commit23830f19a30785e01b5bd08254a62d3563bf2126 (patch)
tree57f646620bfbce7cfefbf26efdd151dab4cc48aa
parent4db97527425020fa7fabe4baa22fb81afc5a1c70 (diff)
Try to use smaller mmapped buffers on Ethernet devices.
Unfortunately, setting the frame size for mmapped captures based only on the snapshot length means we end up with very large frames with the usual large "capture the entire packet" snapshot length, which means very *few* frames as the frames in the mmapped buffer are fixed length, and thus perhaps more packet drops. It's hard to choose the right frame size in the general case, but we try clamping it at MTU+18 for Ethernet, at least.
-rw-r--r--pcap-linux.c42
1 files changed, 35 insertions, 7 deletions
diff --git a/pcap-linux.c b/pcap-linux.c
index 24ad49f2..fea9797a 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -3199,6 +3199,7 @@ create_ring(pcap_t *handle, int *status)
struct tpacket_req req;
socklen_t len;
unsigned int sk_type, tp_reserve, maclen, tp_hdrlen, netoff, macoff;
+ unsigned int frame_size;
/*
* Start out assuming no warnings or errors.
@@ -3207,15 +3208,42 @@ create_ring(pcap_t *handle, int *status)
/* Note that with large snapshot length (say 64K, which is the default
* for recent versions of tcpdump, the value that "-s 0" has given
- * for a long time with tcpdump, and the default in Wireshark/TShark)
+ * for a long time with tcpdump, and the default in Wireshark/TShark),
+ * if we use the snapshot length to calculate the frame length,
* only a few frames will be available in the ring even with pretty
* large ring size (and a lot of memory will be unused).
*
- * The snapshot length should be carefully chosen to achive best
- * performance; good luck with that if you're capturing on, for
- * example, a monitor-mode device, as the radiotap header counts
- * against the snapshot length, and the maximum radiotap header
- * length is device-dependent. */
+ * Ideally, we should choose a frame length based on the
+ * minimum of the specified snapshot length and the maximum
+ * packet size. That's not as easy as it sounds; consider, for
+ * example, an 802.11 interface in monitor mode, where the
+ * frame would include a radiotap header, where the maximum
+ * radiotap header length is device-dependent.
+ *
+ * So, for now, we just do this for Ethernet devices, where
+ * there's no metadata header, and the link-layer header is
+ * fixed length. We can get the maximum packet size by
+ * adding 18, the Ethernet header length plus the CRC length
+ * (just in case we happen to get the CRC in the packet), to
+ * the MTU of the interface; we fetch the MTU in the hopes
+ * that it reflects support for jumbo frames. (Even if the
+ * interface is just being used for passive snooping, the driver
+ * might set the size of buffers in the receive ring based on
+ * the MTU, so that the MTU limits the maximum size of packets
+ * that we can receive.) */
+ frame_size = handle->snapshot;
+ if (handle->linktype == DLT_EN10MB) {
+ int mtu;
+
+ mtu = iface_get_mtu(handle->fd, handle->opt.source,
+ handle->errbuf);
+ if (mtu == -1) {
+ *status = PCAP_ERROR;
+ return -1;
+ }
+ if (frame_size > mtu + 18)
+ frame_size = mtu + 18;
+ }
/* NOTE: calculus matching those in tpacket_rcv()
* in linux-2.6/net/packet/af_packet.c
@@ -3273,7 +3301,7 @@ create_ring(pcap_t *handle, int *status)
* when accessing unaligned memory locations"
*/
macoff = netoff - maclen;
- req.tp_frame_size = TPACKET_ALIGN(macoff + handle->snapshot);
+ req.tp_frame_size = TPACKET_ALIGN(macoff + frame_size);
req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size;
/* compute the minumum block size that will handle this frame.