Merge branch 'master' of github.com:borkmann/netsniff-ng
[netsniff-ng.git] / pcap_sg.c
blobb8e9d719b47f48cd3dc3ac6ae1ee31c5cbfd73f3
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 - 2013 Daniel Borkmann.
5 * Subject to the GPL, version 2.
6 */
8 #include <stdio.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <sys/uio.h>
13 #include <unistd.h>
15 #include "pcap.h"
16 #include "xmalloc.h"
17 #include "xio.h"
18 #include "xutils.h"
19 #include "built_in.h"
21 static struct iovec iov[1024] __cacheline_aligned;
22 static off_t iov_off_rd = 0, iov_slot = 0;
24 static ssize_t pcap_sg_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
25 const uint8_t *packet, size_t len)
27 ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type);
29 if (unlikely(iov_slot == array_size(iov))) {
30 ret = writev(fd, iov, array_size(iov));
31 if (ret < 0)
32 panic("Writev I/O error: %s!\n", strerror(errno));
34 iov_slot = 0;
37 fmemcpy(iov[iov_slot].iov_base, &phdr->raw, hdrsize);
38 iov[iov_slot].iov_len = hdrsize;
40 fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
41 ret = (iov[iov_slot].iov_len += len);
43 iov_slot++;
44 return ret;
47 static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
48 uint8_t *packet, size_t len, size_t hdrsize)
50 int ret;
51 size_t offset = 0;
52 ssize_t remainder;
54 offset = iov[iov_slot].iov_len - iov_off_rd;
55 remainder = hdrsize - offset;
56 if (remainder < 0)
57 remainder = 0;
59 bug_on(offset + remainder != hdrsize);
61 fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, offset);
62 iov_off_rd = 0;
63 iov_slot++;
65 if (iov_slot == array_size(iov)) {
66 iov_slot = 0;
67 ret = readv(fd, iov, array_size(iov));
68 if (unlikely(ret <= 0))
69 return -EIO;
72 fmemcpy(&phdr->raw + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
73 iov_off_rd += remainder;
75 return hdrsize;
78 static ssize_t __pcap_sg_inter_iov_data_read(int fd, uint8_t *packet, size_t len, size_t hdrlen)
80 int ret;
81 size_t offset = 0;
82 ssize_t remainder;
84 offset = iov[iov_slot].iov_len - iov_off_rd;
85 remainder = hdrlen - offset;
86 if (remainder < 0)
87 remainder = 0;
89 bug_on(offset + remainder != hdrlen);
91 fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, offset);
92 iov_off_rd = 0;
93 iov_slot++;
95 if (iov_slot == array_size(iov)) {
96 iov_slot = 0;
97 ret = readv(fd, iov, array_size(iov));
98 if (unlikely(ret <= 0))
99 return -EIO;
102 fmemcpy(packet + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
103 iov_off_rd += remainder;
105 return hdrlen;
108 static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
109 uint8_t *packet, size_t len)
111 ssize_t ret = 0;
112 size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
114 if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrsize)) {
115 fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, hdrsize);
116 iov_off_rd += hdrsize;
117 } else {
118 ret = __pcap_sg_inter_iov_hdr_read(fd, phdr, type, packet,
119 len, hdrsize);
120 if (unlikely(ret < 0))
121 return ret;
124 hdrlen = pcap_get_length(phdr, type);
125 if (unlikely(hdrlen == 0 || hdrlen > len))
126 return -EINVAL;
128 if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrlen)) {
129 fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, hdrlen);
130 iov_off_rd += hdrlen;
131 } else {
132 ret = __pcap_sg_inter_iov_data_read(fd, packet, len, hdrlen);
133 if (unlikely(ret < 0))
134 return ret;
137 return hdrsize + hdrlen;
140 static void pcap_sg_fsync(int fd)
142 ssize_t ret = writev(fd, iov, iov_slot);
143 if (ret < 0)
144 panic("Writev I/O error: %s!\n", strerror(errno));
146 iov_slot = 0;
147 fdatasync(fd);
150 static int pcap_sg_prepare_access(int fd, enum pcap_mode mode, bool jumbo)
152 int i, ret;
153 size_t len = 0;
155 iov_slot = 0;
156 len = jumbo ? (PAGE_SIZE * 16) /* 64k max */ :
157 (PAGE_SIZE * 3) /* 12k max */;
159 for (i = 0; i < array_size(iov); ++i) {
160 iov[i].iov_base = xzmalloc_aligned(len, 64);
161 iov[i].iov_len = len;
164 set_ioprio_rt();
166 if (mode == PCAP_MODE_RD) {
167 ret = readv(fd, iov, array_size(iov));
168 if (ret <= 0)
169 return -EIO;
171 iov_off_rd = 0;
172 iov_slot = 0;
175 return 0;
178 static void pcap_sg_prepare_close(int fd, enum pcap_mode mode)
180 int i;
182 for (i = 0; i < array_size(iov); ++i)
183 xfree(iov[i].iov_base);
186 const struct pcap_file_ops pcap_sg_ops = {
187 .pull_fhdr_pcap = pcap_generic_pull_fhdr,
188 .push_fhdr_pcap = pcap_generic_push_fhdr,
189 .prepare_access_pcap = pcap_sg_prepare_access,
190 .prepare_close_pcap = pcap_sg_prepare_close,
191 .read_pcap = pcap_sg_read,
192 .write_pcap = pcap_sg_write,
193 .fsync_pcap = pcap_sg_fsync,