All of lore.kernel.org
 help / color / mirror / Atom feed
From: Patrick McHardy <kaber@trash.net>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org
Subject: Re: [PATCH 00/08]: VLAN update
Date: Wed, 09 Jul 2008 14:12:26 +0200	[thread overview]
Message-ID: <4874AB2A.7000704@trash.net> (raw)
In-Reply-To: <20080709120945.11669.42790.sendpatchset@localhost.localdomain>

[-- Attachment #1: Type: text/plain, Size: 549 bytes --]

Patrick McHardy wrote:
> These patches include an updated set of the VLAN packet socket fixes,
> now also supporting VLAN TCI delivery to userspace using mmaped packet
> sockets, as well as a patch to add ->get_flags ethtool support and
> a few minor cleanup patches.

And for reference, attached is a patch for libpcap to reconstruct
the VLAN header from the auxdata, as well as a ugly small program
for testing the new mmaped packet socket protocol version (since I
couldn't find a version of libpcap that already supports this for
some reason).


[-- Attachment #2: libpcap.diff --]
[-- Type: text/x-diff, Size: 3176 bytes --]

diff --git a/pcap-linux.c b/pcap-linux.c
index e9db010..e877cd8 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -471,7 +471,13 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 	socklen_t		fromlen;
 	int			packet_len, caplen;
 	struct pcap_pkthdr	pcap_header;
-
+	struct iovec		iov;
+	struct msghdr		msg;
+	struct cmsghdr		*cmsg;
+	union {
+		struct cmsghdr	cmsg;
+		char		buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))];
+	} cmsg_buf;
 #ifdef HAVE_PF_PACKET_SOCKETS
 	/*
 	 * If this is a cooked device, leave extra room for a
@@ -492,6 +498,15 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 	/* Receive a single packet from the kernel */
 
 	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		= &cmsg_buf;
+	msg.msg_controllen	= sizeof(cmsg_buf);
+	msg.msg_flags		= 0;
+
 	do {
 		/*
 		 * Has "pcap_breakloop()" been called?
@@ -505,11 +520,11 @@ 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);
+
+		iov.iov_len	= handle->bufsize - offset;
+		iov.iov_base	= bp + offset;
+
+		packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC);
 	} while (packet_len == -1 && errno == EINTR);
 
 	/* Check if an error occured */
@@ -524,6 +539,38 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 		}
 	}
 
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		struct tpacket_auxdata *aux;
+		unsigned int len, copy;
+		unsigned short *ptr;
+
+		if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
+		    cmsg->cmsg_level != SOL_PACKET ||
+		    cmsg->cmsg_type != PACKET_AUXDATA)
+			continue;
+
+		aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
+		if (aux->tp_vlan_tci == 0)
+			continue;
+
+		len = packet_len > iov.iov_len ? iov.iov_len : packet_len;
+		if (len > 2 * ETH_ALEN + 4) {
+			copy = len - 2 * ETH_ALEN - 4;
+			if (copy > iov.iov_len - 2 * ETH_ALEN - 4)
+				copy = iov.iov_len - 2 * ETH_ALEN - 4;
+
+			memmove(iov.iov_base + 2 * ETH_ALEN + 4,
+				iov.iov_base + 2 * ETH_ALEN, copy);
+		}
+
+		ptr = (unsigned short *)(iov.iov_base + 2 * ETH_ALEN);
+		if (len >= 2 * ETH_ALEN + 2)
+			*(ptr++) = htons(ETH_P_8021Q);
+		if (len >= 2 * ETH_ALEN + 4)
+			*(ptr++) = htons(aux->tp_vlan_tci);
+		packet_len += 4;
+	}
+
 #ifdef HAVE_PF_PACKET_SOCKETS
 	if (!handle->md.sock_packet) {
 		/*
@@ -1631,6 +1678,7 @@ iface_bind(int fd, int ifindex, char *ebuf)
 	struct sockaddr_ll	sll;
 	int			err;
 	socklen_t		errlen = sizeof(err);
+	int			val;
 
 	memset(&sll, 0, sizeof(sll));
 	sll.sll_family		= AF_PACKET;
@@ -1657,6 +1705,12 @@ iface_bind(int fd, int ifindex, char *ebuf)
 		return -2;
 	}
 
+	val = 1;
+	if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1) {
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			 "setsockopt: %s", pcap_strerror(errno));
+		return -3;
+	}
 	return 0;
 }
 

[-- Attachment #3: mmap-test.diff --]
[-- Type: text/x-diff, Size: 7535 bytes --]

diff -urN /tmp/null/if_packet.h mmap-test/if_packet.h
--- /tmp/null/if_packet.h	1970-01-01 01:00:00.000000000 +0100
+++ mmap-test/if_packet.h	2008-07-09 12:56:08.000000000 +0200
@@ -0,0 +1,144 @@
+#ifndef __LINUX_IF_PACKET_H
+#define __LINUX_IF_PACKET_H
+
+#include <linux/types.h>
+
+struct sockaddr_pkt
+{
+	unsigned short spkt_family;
+	unsigned char spkt_device[14];
+	__be16 spkt_protocol;
+};
+
+struct sockaddr_ll
+{
+	unsigned short	sll_family;
+	__be16		sll_protocol;
+	int		sll_ifindex;
+	unsigned short	sll_hatype;
+	unsigned char	sll_pkttype;
+	unsigned char	sll_halen;
+	unsigned char	sll_addr[8];
+};
+
+/* Packet types */
+
+#define PACKET_HOST		0		/* To us		*/
+#define PACKET_BROADCAST	1		/* To all		*/
+#define PACKET_MULTICAST	2		/* To group		*/
+#define PACKET_OTHERHOST	3		/* To someone else 	*/
+#define PACKET_OUTGOING		4		/* Outgoing of any type */
+/* These ones are invisible by user level */
+#define PACKET_LOOPBACK		5		/* MC/BRD frame looped back */
+#define PACKET_FASTROUTE	6		/* Fastrouted frame	*/
+
+/* Packet socket options */
+
+#define PACKET_ADD_MEMBERSHIP		1
+#define PACKET_DROP_MEMBERSHIP		2
+#define PACKET_RECV_OUTPUT		3
+/* Value 4 is still used by obsolete turbo-packet. */
+#define PACKET_RX_RING			5
+#define PACKET_STATISTICS		6
+#define PACKET_COPY_THRESH		7
+#define PACKET_AUXDATA			8
+#define PACKET_ORIGDEV			9
+#define PACKET_VERSION			10
+#define PACKET_HDRLEN			11
+
+struct tpacket_stats
+{
+	unsigned int	tp_packets;
+	unsigned int	tp_drops;
+};
+
+struct tpacket_auxdata
+{
+	__u32		tp_status;
+	__u32		tp_len;
+	__u32		tp_snaplen;
+	__u16		tp_mac;
+	__u16		tp_net;
+	__u16		tp_vlan_tci;
+};
+
+struct tpacket_hdr
+{
+	unsigned long	tp_status;
+#define TP_STATUS_KERNEL	0
+#define TP_STATUS_USER		1
+#define TP_STATUS_COPY		2
+#define TP_STATUS_LOSING	4
+#define TP_STATUS_CSUMNOTREADY	8
+	unsigned int	tp_len;
+	unsigned int	tp_snaplen;
+	unsigned short	tp_mac;
+	unsigned short	tp_net;
+	unsigned int	tp_sec;
+	unsigned int	tp_usec;
+};
+
+#define TPACKET_ALIGNMENT	16
+#define TPACKET_ALIGN(x)	(((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1))
+#define TPACKET_HDRLEN		(TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + sizeof(struct sockaddr_ll))
+
+struct tpacket2_hdr
+{
+	__u32		tp_status;
+	__u32		tp_len;
+	__u32		tp_snaplen;
+	__u16		tp_mac;
+	__u16		tp_net;
+	__u32		tp_sec;
+	__u32		tp_nsec;
+#ifdef TEST_VLAN_TCI
+	__u16		tp_vlan_tci;
+#endif
+};
+
+#ifdef __KERNEL__
+#define TPACKET2_HDRLEN		(TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll))
+#else
+#define TPACKET2_HDRLEN(x)	(TPACKET_ALIGN(x) + sizeof(struct sockaddr_ll))
+#endif
+
+enum tpacket_versions
+{
+	TPACKET_V1,
+	TPACKET_V2,
+};
+
+/*
+   Frame structure:
+
+   - Start. Frame must be aligned to TPACKET_ALIGNMENT=16
+   - struct tpacket_hdr
+   - pad to TPACKET_ALIGNMENT=16
+   - struct sockaddr_ll
+   - Gap, chosen so that packet data (Start+tp_net) alignes to TPACKET_ALIGNMENT=16
+   - Start+tp_mac: [ Optional MAC header ]
+   - Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
+   - Pad to align to TPACKET_ALIGNMENT=16
+ */
+
+struct tpacket_req
+{
+	unsigned int	tp_block_size;	/* Minimal size of contiguous block */
+	unsigned int	tp_block_nr;	/* Number of blocks */
+	unsigned int	tp_frame_size;	/* Size of frame */
+	unsigned int	tp_frame_nr;	/* Total number of frames */
+};
+
+struct packet_mreq
+{
+	int		mr_ifindex;
+	unsigned short	mr_type;
+	unsigned short	mr_alen;
+	unsigned char	mr_address[8];
+};
+
+#define PACKET_MR_MULTICAST	0
+#define PACKET_MR_PROMISC	1
+#define PACKET_MR_ALLMULTI	2
+
+#endif
diff -urN /tmp/null/Makefile mmap-test/Makefile
--- /tmp/null/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ mmap-test/Makefile	2008-07-09 03:21:21.000000000 +0200
@@ -0,0 +1,3 @@
+CFLAGS	+= -O2 -I. -Wall -g
+
+all: test
diff -urN /tmp/null/test.c mmap-test/test.c
--- /tmp/null/test.c	1970-01-01 01:00:00.000000000 +0100
+++ mmap-test/test.c	2008-07-09 12:56:40.000000000 +0200
@@ -0,0 +1,150 @@
+#include <unistd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <arpa/inet.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/if_ether.h>
+
+#define V2
+#ifdef V2
+#define TEST_VLAN_TCI 1
+#endif
+
+#include "if_packet.h"
+
+int main(int argc, char **argv)
+{
+	struct sockaddr_ll lladdr;
+	struct tpacket_req req;
+#ifdef V2
+	struct tpacket2_hdr *hdr;
+#else
+	struct tpacket_hdr *hdr;
+#endif
+	unsigned int hdrlen;
+	int val;
+	socklen_t len;
+	void *ring;
+	unsigned int head;
+	unsigned int total = 0;
+	int fd;
+
+	fd = socket(AF_PACKET, SOCK_RAW, 0);
+	if (fd < 0) {
+		perror("socket");
+		return 1;
+	}
+
+#ifdef V2
+	val = TPACKET_V2;
+	len = sizeof(val);
+	if (getsockopt(fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) {
+		perror("setsockopt(PACKET_HDRLEN)");
+		return 1;
+	}
+	hdrlen = val;
+
+	printf("hdrlen=%u sizeof(struct tpacket2_hdr)=%Zu\n",
+		hdrlen, sizeof(struct tpacket2_hdr));
+
+	val = TPACKET_V2;
+	if (setsockopt(fd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) {
+		perror("setsockopt(PACKET_VERSION)");
+		return 1;
+	}
+#else
+	hdrlen = sizeof(struct tpacket_hdr);
+#endif
+
+	memset(&req, 0, sizeof(req));
+	req.tp_block_size	= 16 * 4096;
+	req.tp_block_nr		= 16;
+	req.tp_frame_size	= 1024;
+	req.tp_frame_nr		= 16 * 64;
+
+	if (setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) < 0) {
+		perror("setsockopt");
+		return 1;
+	}
+
+	ring = mmap(NULL, req.tp_block_nr * req.tp_block_size,
+		    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if ((long)ring == -1L) {
+		perror("mmap");
+		return 1;
+	}
+
+	memset(&lladdr, 0, sizeof(lladdr));
+	lladdr.sll_family = AF_PACKET;
+	lladdr.sll_protocol = htons(ETH_P_ALL);
+	lladdr.sll_ifindex = 2;
+
+	if (bind(fd, (struct sockaddr *)&lladdr, sizeof(lladdr)) < 0) {
+		perror("bind");
+		return 1;
+	}
+
+	hdr = ring;
+	head = 0;
+
+	while (1) {
+		unsigned int cnt = 0;
+		struct pollfd pfds[1];
+
+		pfds[0].fd	= fd;
+		pfds[0].events	= POLLIN | POLLERR;
+		pfds[0].revents	= 0;
+
+		if (poll(pfds, 1, -1) < 0 && errno != EINTR) {
+			perror("poll");
+			return 1;
+		}
+
+		if (pfds[0].revents & POLLERR) {
+			char buf[16384];
+			recv(fd, buf, sizeof(buf), MSG_DONTWAIT | MSG_ERRQUEUE);
+			printf("error %d\n", errno);
+			continue;
+		}
+
+		if (!(pfds[0].revents & POLLIN))
+			continue;
+
+		while (hdr->tp_status != TP_STATUS_KERNEL) {
+			struct sockaddr_ll *sll;
+			unsigned char *data = (void *)hdr + hdr->tp_mac;
+			unsigned int i;
+
+			printf("%.4u ring[%u]: tp_status=%u tp_len=%u "
+			       "tp_snaplen=%u\n",
+				total, head, hdr->tp_status, hdr->tp_len, hdr->tp_snaplen);
+#ifdef TEST_VLAN_TCI
+			printf("tp_vlan_tci=%u id=%u\n",
+			       hdr->tp_vlan_tci, hdr->tp_vlan_tci & 0xfff);
+#endif
+			for (i = 0; i < (hdr->tp_snaplen > 32 ? 32 : hdr->tp_snaplen); i++)
+				printf("%.2x ", data[i]);
+			printf("\n");
+
+			sll = (void *)hdr + TPACKET_ALIGN(hdrlen);
+			printf("sll_family=%u sll_protocol=%u sll_ifindex=%d sll_hatype=%u "
+			       "sll_pkttype=%u sll_halen=%u\n",
+			       sll->sll_family, ntohs(sll->sll_protocol),
+			       sll->sll_ifindex, sll->sll_hatype,
+			       sll->sll_pkttype, sll->sll_halen);
+			hdr->tp_status = TP_STATUS_KERNEL;
+
+			head = head == req.tp_frame_nr - 1 ? 0 : head + 1;
+			hdr = ring + head * req.tp_frame_size;
+			cnt++, total++;
+		}
+		printf("received %u consecutive entries, %u total\n\n", cnt, total);
+	}
+	return 0;
+}

  parent reply	other threads:[~2008-07-09 12:12 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-09 12:09 [PATCH 00/08]: VLAN update Patrick McHardy
2008-07-09 12:09 ` [PATCH 01/08]: vlan: Don't store VLAN tag in cb Patrick McHardy
2008-07-09 12:09 ` [PATCH 02/08]: vlan: deliver packets received with VLAN acceleration to network taps Patrick McHardy
2008-07-09 12:35   ` Ben Hutchings
2008-07-09 12:37     ` Patrick McHardy
2008-07-09 12:09 ` [PATCH 03/08]: packet: support extensible, 64 bit clean mmaped ring structure Patrick McHardy
2008-07-09 12:09 ` [PATCH 04/08]: packet: deliver VLAN TCI to userspace Patrick McHardy
2008-07-09 12:09 ` [PATCH 05/08]: vlan: ethtool ->get_flags support Patrick McHardy
2008-07-09 12:09 ` [PATCH 06/08]: vlan: clean up vlan_dev_hard_header() Patrick McHardy
2008-07-09 12:09 ` [PATCH 07/08]: vlan: clean up hard_start_xmit functions Patrick McHardy
2008-07-09 12:09 ` [PATCH 08/08]: vlan: remove unnecessary include statements Patrick McHardy
2008-07-09 12:12 ` Patrick McHardy [this message]
2008-07-15  5:56 ` [PATCH 00/08]: VLAN update David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4874AB2A.7000704@trash.net \
    --to=kaber@trash.net \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.