Skip to contentSkip to conversation

libpcap VLAN accel support

PATCH Patrick McHardy 1 participant 1 message Jul 18, 2008

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

In case someone is interested, I just sent these patches for VLAN accel support to the libpcap maintainers.

The latest CVS version includes support for mmaped packet sockets, so I also added support for this (this was missing from the example patch I posted earlier since it was based on an old Debian version).

Also the payload is not moved anymore when reconstructing the VLAN headers, only the ethernet addresses are moved further to the front to make room for the VLAN header.

pcap-linux: fix invalid rcvbuf size

From: Patrick McHardy <[email protected]>

Libpcap issues a SO_RCVBUF when the buffer size if unspecified (zero). The intention appears to be to set it when its *not* zero.
---

 pcap-linux.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
pcap-linux.c +1 -1
index d9f9f10..d4c06cb 100644
@@ -557,7 +557,7 @@ pcap_activate_linux(pcap_t *handle)
 		goto fail;
 	}
 
-	if (handle->opt.buffer_size == 0) {
+	if (handle->opt.buffer_size != 0) {
 		/*
 		 * Set the socket buffer size to the specified value.
 		 */

pcap-linux: convert to recvmsg()

From: Patrick McHardy <[email protected]>

Convert pcap-linux to use recvmsg() as preparation for using PACKET_AUXDATA cmsgs.
---

 pcap-linux.c |   23 ++++++++++++++++-------
 1 files changed, 16 insertions(+), 7 deletions(-)
pcap-linux.c +16 -7
index d4c06cb..aac9b11 100644
@@ -625,10 +625,10 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 #else
 	struct sockaddr		from;
 #endif
-	socklen_t		fromlen;
 	int			packet_len, caplen;
 	struct pcap_pkthdr	pcap_header;
-
+	struct iovec		iov;
+	struct msghdr		msg;
 #ifdef HAVE_PF_PACKET_SOCKETS
 	/*
 	 * If this is a cooked device, leave extra room for a
@@ -662,6 +662,18 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 	 * get notified of "network down" events.
 	 */
 	bp = handle->buffer + handle->offset;
+
+	msg.msg_name		= &from;
+	msg.msg_namelen		= sizeof(from);
+	msg.msg_iov		= &iov;
+	msg.msg_iovlen		= 1;
+	msg.msg_control		= NULL;
+	msg.msg_controllen	= 0;
+	msg.msg_flags		= 0;
+
+	iov.iov_len		= handle->bufsize - offset;
+	iov.iov_base		= bp + offset;
+
 	do {
 		/*
 		 * Has "pcap_breakloop()" been called?
@@ -675,11 +687,8 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 			handle->break_loop = 0;
 			return -2;
 		}
-		fromlen = sizeof(from);
-		packet_len = recvfrom(
-			handle->fd, bp + offset,
-			handle->bufsize - offset, MSG_TRUNC,
-			(struct sockaddr *) &from, &fromlen);
+
+		packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC);
 	} while (packet_len == -1 && (errno == EINTR || errno == ENETDOWN));
 
 	/* Check if an error occured */

pcap-linux: reconstruct VLAN header from PACKET_AUXDATA

From: Patrick McHardy <[email protected]>

VLAN packets sent over devices supporting VLAN tagging/stripping in hardwaredon't have a VLAN header when they are received on packet sockets. The VLAN TCI is available through the PACKET_AUXDATA cmsg, reconstruct the entire header when necessary.
---

 pcap-linux.c |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 pcap/vlan.h  |   11 +++++++++++
 2 files changed, 67 insertions(+), 3 deletions(-)
 create mode 100644 pcap/vlan.h
pcap-linux.c +56 -3

101 lines not on this page · raw message

pcap/vlan.h new file +11 -0
new file mode 100644
index 0000000..2a47ca2
@@ -0,0 +1,11 @@
+#ifndef lib_pcap_vlan_h
+#define lib_pcap_vlan_h
+
+struct vlan_tag {
+	u_int16_t	vlan_tpid;		/* ETH_P_8021Q */
+	u_int16_t	vlan_tci;		/* VLAN TCI */
+};
+
+#define VLAN_TAG_LEN	4
+
+#endif

pcap-linux: support new tpacket frame header format

From: Patrick McHardy <[email protected]>

The tpacket_hdr is not clean for 64 bit kernel/32 bit userspace and is not extendable because the struct sockaddr_ll following it is expected at a fixed offset.

Linux 2.6.27-rc supports a new tpacket frame header that removes these two limitations. Convert the mmap ring support to support both formats and probe for availability of the new version.
---

 pcap-int.h   |    2 +
 pcap-linux.c |  152 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 134 insertions(+), 20 deletions(-)
pcap-int.h +2 -0
index 4de319c..97238fd 100644
@@ -132,6 +132,8 @@ struct pcap_md {
 	int	lo_ifindex;	/* interface index of the loopback device */
 	u_int	packets_read;	/* count of packets read with recvfrom() */
 	bpf_u_int32 oldmode;	/* mode to restore when turning monitor mode off */
+	u_int	tp_version;	/* version of tpacket_hdr for mmaped ring */
+	u_int	tp_hdrlen;	/* hdrlen of tpacket_hdr for mmaped ring */
 #endif /* linux */
 
 #ifdef HAVE_DAG_API
pcap-linux.c +132 -20

259 lines not on this page · raw message

pcap-linux: reconstruct VLAN headers from tpacket2_hdr

From: Patrick McHardy <[email protected]>

Similar to PACKET_AUXDATA for non-mmaped sockets, the VLAN TCI is present in a new member of struct tpacket2_hdr. Use it to reconstruct the VLAN header when necessary.
---

 pcap-linux.c |   28 ++++++++++++++++++++++++++++
 1 files changed, 28 insertions(+), 0 deletions(-)
pcap-linux.c +28 -0
index 52d9bd8..bd01774 100644
@@ -1965,6 +1965,17 @@ prepare_tpacket_socket(pcap_t *handle)
 		return 0;
 	}
 	handle->md.tp_version = TPACKET_V2;
+
+	/* Reserve space for VLAN tag reconstruction */
+	val = VLAN_TAG_LEN;
+	if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &val,
+		       sizeof(val)) < 0) {
+		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+			 "can't set up reserve on socket %d: %d-%s",
+			 handle->fd, errno, pcap_strerror(errno));
+		return 0;
+	}
+
 #endif /* HAVE_TPACKET2 */
 	return 1;
 }
@@ -2281,6 +2292,23 @@ pcap_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback,
 			pcaphdr.len += SLL_HDR_LEN;
 		}
 
+#ifdef HAVE_TPACKET2
+		if (handle->md.tp_version == TPACKET_V2 && h.h2->tp_vlan_tci &&
+		    tp_snaplen >= 2 * ETH_ALEN) {
+			struct vlan_tag *tag;
+
+			bp -= VLAN_TAG_LEN;
+			memmove(bp, bp + VLAN_TAG_LEN, 2 * ETH_ALEN);
+
+			tag = (struct vlan_tag *)(bp + 2 * ETH_ALEN);
+			tag->vlan_tpid = htons(ETH_P_8021Q);
+			tag->vlan_tci = htons(h.h2->tp_vlan_tci);
+
+			pcaphdr.caplen += VLAN_TAG_LEN;
+			pcaphdr.len += VLAN_TAG_LEN;
+		}
+#endif
+
 		/* pass the packet to the user */
 		pkts++;
 		callback(user, &pcaphdr, bp);