proto_icmpv6.h: intermediate state
[netsniff-ng.git] / src / pcap_sg.c
blob17e6819ecfee97eeab46558dc46750ec5dcdf158
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 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 "xsys.h"
19 #include "locking.h"
20 #include "built_in.h"
22 #define PAGE_SIZE (getpagesize())
23 #define PAGE_MASK (~(PAGE_SIZE - 1))
24 #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
26 #define IOVSIZ 1000
27 #define ALLSIZ (PAGE_SIZE * 3)
28 #define ALLSIZ_2K (PAGE_SIZE * 3) // 12K max
29 #define ALLSIZ_JUMBO (PAGE_SIZE * 16) // 64K max
31 static struct iovec iov[IOVSIZ];
32 static unsigned long c = 0;
33 static struct spinlock lock;
34 static ssize_t avail, used, iov_used;
36 static int pcap_sg_pull_file_header(int fd)
38 ssize_t ret;
39 struct pcap_filehdr hdr;
41 ret = read(fd, &hdr, sizeof(hdr));
42 if (unlikely(ret != sizeof(hdr)))
43 return -EIO;
45 ret = pcap_validate_header(&hdr);
46 if (ret < 0)
47 lseek(fd, -sizeof(hdr), SEEK_CUR);
49 return 0;
52 static int pcap_sg_push_file_header(int fd)
54 ssize_t ret;
55 struct pcap_filehdr hdr;
57 fmemset(&hdr, 0, sizeof(hdr));
58 pcap_prepare_header(&hdr, LINKTYPE_EN10MB, 0,
59 PCAP_DEFAULT_SNAPSHOT_LEN);
60 ret = write_or_die(fd, &hdr, sizeof(hdr));
61 if (unlikely(ret != sizeof(hdr))) {
62 whine("Failed to write pkt file header!\n");
63 return -EIO;
66 return 0;
69 static int pcap_sg_prepare_writing_pcap(int fd)
71 set_ioprio_be();
72 return 0;
75 static ssize_t pcap_sg_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
76 uint8_t *packet, size_t len)
78 ssize_t ret;
80 spinlock_lock(&lock);
82 if (unlikely(c == IOVSIZ)) {
83 ret = writev(fd, iov, IOVSIZ);
84 if (ret < 0)
85 panic("writev I/O error!\n");
87 c = 0;
90 iov[c].iov_len = 0;
91 fmemcpy(iov[c].iov_base, hdr, sizeof(*hdr));
93 iov[c].iov_len += sizeof(*hdr);
94 fmemcpy(iov[c].iov_base + iov[c].iov_len, packet, len);
96 iov[c].iov_len += len;
97 ret = iov[c].iov_len;
99 c++;
101 spinlock_unlock(&lock);
103 return ret;
106 static int pcap_sg_prepare_reading_pcap(int fd)
108 set_ioprio_be();
110 spinlock_lock(&lock);
112 avail = readv(fd, iov, IOVSIZ);
113 if (avail <= 0)
114 return -EIO;
116 used = iov_used = 0;
117 c = 0;
119 spinlock_unlock(&lock);
121 return 0;
124 static ssize_t pcap_sg_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
125 uint8_t *packet, size_t len)
127 /* In contrast to writing, reading gets really ugly ... */
128 spinlock_lock(&lock);
130 if (likely(avail - used >= sizeof(*hdr) &&
131 iov[c].iov_len - iov_used >= sizeof(*hdr))) {
133 fmemcpy(hdr, iov[c].iov_base + iov_used, sizeof(*hdr));
134 iov_used += sizeof(*hdr);
136 used += sizeof(*hdr);
138 } else {
139 size_t remainder, offset = 0;
141 if (avail - used < sizeof(*hdr))
142 return -ENOMEM;
144 offset = iov[c].iov_len - iov_used;
145 remainder = sizeof(*hdr) - offset;
147 bug_on(offset + remainder != sizeof(*hdr));
149 fmemcpy(hdr, iov[c].iov_base + iov_used, offset);
150 used += offset;
152 iov_used = 0;
153 c++;
155 if (c == IOVSIZ) {
156 /* We need to refetch! */
157 c = 0;
159 avail = readv(fd, iov, IOVSIZ);
160 if (avail < 0)
161 return -EIO;
163 used = 0;
166 /* Now we copy the remainder and go on with business ... */
167 fmemcpy(hdr, iov[c].iov_base + iov_used, remainder);
168 iov_used += remainder;
170 used += remainder;
172 if (likely(avail - used >= hdr->len &&
173 iov[c].iov_len - iov_used >= hdr->len)) {
175 fmemcpy(packet, iov[c].iov_base + iov_used, hdr->len);
176 iov_used += hdr->len;
178 used += hdr->len;
180 } else {
181 size_t remainder, offset = 0;
183 if (avail - used < hdr->len)
184 return -ENOMEM;
186 offset = iov[c].iov_len - iov_used;
187 remainder = hdr->len - offset;
189 bug_on(offset + remainder != hdr->len);
191 fmemcpy(packet, iov[c].iov_base + iov_used, offset);
192 used += offset;
194 iov_used = 0;
195 c++;
197 if (c == IOVSIZ) {
198 /* We need to refetch! */
199 c = 0;
201 avail = readv(fd, iov, IOVSIZ);
202 if (avail < 0)
203 return -EIO;
205 used = 0;
208 /* Now we copy the remainder and go on with business ... */
209 fmemcpy(packet, iov[c].iov_base + iov_used, remainder);
210 iov_used += remainder;
212 used += remainder;
215 spinlock_unlock(&lock);
217 if (unlikely(hdr->len == 0))
218 return -EINVAL; /* Bogus packet */
220 return sizeof(*hdr) + hdr->len;
223 static void pcap_sg_fsync_pcap(int fd)
225 ssize_t ret;
227 spinlock_lock(&lock);
229 ret = writev(fd, iov, c);
230 if (ret < 0)
231 panic("writev I/O error!\n");
233 c = 0;
235 fdatasync(fd);
237 spinlock_unlock(&lock);
240 struct pcap_file_ops pcap_sg_ops __read_mostly = {
241 .name = "scatter-gather",
242 .pull_file_header = pcap_sg_pull_file_header,
243 .push_file_header = pcap_sg_push_file_header,
244 .write_pcap_pkt = pcap_sg_write_pcap_pkt,
245 .prepare_reading_pcap = pcap_sg_prepare_reading_pcap,
246 .prepare_writing_pcap = pcap_sg_prepare_writing_pcap,
247 .read_pcap_pkt = pcap_sg_read_pcap_pkt,
248 .fsync_pcap = pcap_sg_fsync_pcap,
251 int init_pcap_sg(int jumbo_support)
253 unsigned long i;
254 size_t allocsz = 0;
256 c = 0;
258 fmemset(iov, 0, sizeof(iov));
260 if (jumbo_support)
261 allocsz = ALLSIZ_JUMBO;
262 else
263 allocsz = ALLSIZ_2K;
265 for (i = 0; i < IOVSIZ; ++i) {
266 iov[i].iov_base = xmalloc_aligned(allocsz, 64);
267 iov[i].iov_len = allocsz;
270 spinlock_init(&lock);
272 return pcap_ops_group_register(&pcap_sg_ops, PCAP_OPS_SG);
275 void cleanup_pcap_sg(void)
277 unsigned long i;
279 spinlock_destroy(&lock);
281 for (i = 0; i < IOVSIZ; ++i)
282 xfree(iov[i].iov_base);
284 pcap_ops_group_unregister(PCAP_OPS_SG);