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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}