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;
+}
next prev 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).