diff options
Diffstat (limited to 'ring.h')
-rw-r--r-- | ring.h | 174 |
1 files changed, 174 insertions, 0 deletions
@@ -0,0 +1,174 @@ +/* + * netsniff-ng - the packet sniffing beast + * Copyright 2009, 2010 Daniel Borkmann. + * Subject to the GPL, version 2. + */ + +#ifndef RING_H +#define RING_H + +/* + * "I love the smell of 10GbE in the morning. Smells like ... victory." + * - W. Richard Stevens, "Secret Teachings of the UNIX Environment" + */ + +#include <stdio.h> +#include <stdint.h> +#include <linux/if_packet.h> +#include <linux/socket.h> +#include <linux/sockios.h> +#include <sys/ioctl.h> +#include <string.h> +#include <poll.h> +#include <sys/poll.h> + +#include "xutils.h" +#include "built_in.h" +#include "die.h" + +#ifndef PACKET_FANOUT +# define PACKET_FANOUT 18 +# define PACKET_FANOUT_POLICY_HASH 0 +# define PACKET_FANOUT_POLICY_LB 1 +# define PACKET_FANOUT_POLICY_DEFAULT PACKET_FANOUT_HASH +#endif + +struct frame_map { + struct tpacket2_hdr tp_h __aligned_tpacket; + struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket2_hdr)); +}; + +struct ring { + struct iovec *frames; + uint8_t *mm_space; + size_t mm_len; + struct tpacket_req layout; + struct sockaddr_ll s_ll; +}; + +static inline void next_rnd_slot(unsigned int *it, struct ring *ring) +{ + *it = rand() % ring->layout.tp_frame_nr; +} + +#define RING_SIZE_FALLBACK (1 << 26) + +static inline unsigned int ring_size(char *ifname, unsigned int size) +{ + if (size > 0) + return size; + + /* + * Device bitrate in bytes times two as ring size. + * Fallback => ~ 64,00 MB + * 10 MBit => ~ 2,38 MB + * 54 MBit => ~ 12,88 MB + * 100 MBit => ~ 23,84 MB + * 300 MBit => ~ 71,52 MB + * 1.000 MBit => ~ 238,42 MB + * 10.000 MBit => ~ 2.384.18 MB + */ + size = device_bitrate(ifname); + size = (size * 1000000) / 8; + size = size * 2; + if (size == 0) + size = RING_SIZE_FALLBACK; + + return round_up_cacheline(size); +} + +static inline unsigned int ring_frame_size(struct ring *ring) +{ + return ring->layout.tp_frame_size; +} + +static inline void tpacket_hdr_clone(struct tpacket2_hdr *thdrd, + struct tpacket2_hdr *thdrs) +{ + thdrd->tp_sec = thdrs->tp_sec; + thdrd->tp_nsec = thdrs->tp_nsec; + thdrd->tp_snaplen = thdrs->tp_snaplen; + thdrd->tp_len = thdrs->tp_len; +} + +#ifndef POLLRDNORM +# define POLLRDNORM 0x0040 +#endif +#ifndef POLLWRNORM +# define POLLWRNORM 0x0100 +#endif +#ifndef POLLRDHUP +# define POLLRDHUP 0x2000 +#endif + +#define POLL_NEXT_PKT 0 +#define POLL_MOVE_OUT 1 + +static inline void prepare_polling(int sock, struct pollfd *pfd) +{ + memset(pfd, 0, sizeof(*pfd)); + pfd->fd = sock; + pfd->revents = 0; + pfd->events = POLLIN | POLLRDNORM | POLLERR; +} + +static inline void set_sockopt_fanout(int sock, unsigned int fanout_id, + unsigned int fanout_type) +{ + unsigned int fanout_arg = (fanout_id | (fanout_type << 16)); + int ret = setsockopt(sock, SOL_PACKET, PACKET_FANOUT, &fanout_arg, + sizeof(fanout_arg)); + if (ret) + panic("No packet fanout support!\n"); +} + +static inline void set_sockopt_tpacket(int sock) +{ + int ret, val = TPACKET_V2; + + ret = setsockopt(sock, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)); + if (ret) + panic("Cannot set tpacketv2!\n"); +} + +#ifdef __WITH_HARDWARE_TIMESTAMPING +# include <linux/net_tstamp.h> + +static inline void set_sockopt_hwtimestamp(int sock, const char *dev) +{ + int timesource, ret; + struct hwtstamp_config hwconfig; + struct ifreq ifr; + + if (!strncmp("any", dev, strlen("any"))) + return; + + memset(&hwconfig, 0, sizeof(hwconfig)); + hwconfig.tx_type = HWTSTAMP_TX_ON; + hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + ifr.ifr_data = &hwconfig; + + ret = ioctl(sock, SIOCSHWTSTAMP, &ifr); + if (ret < 0) { + if (errno == EOPNOTSUPP) + return; + panic("Cannot set timestamping: %s\n", strerror(errno)); + } + + timesource = SOF_TIMESTAMPING_RAW_HARDWARE; + + ret = setsockopt(sock, SOL_PACKET, PACKET_TIMESTAMP, ×ource, + sizeof(timesource)); + if (ret) + panic("Cannot set timestamping: %s!\n", strerror(errno)); +} +#else +static inline void set_sockopt_hwtimestamp(int sock, const char *dev) +{ + return; +} +#endif +#endif /* RING_H */ |