dissector_eth: also include id into macro
[netsniff-ng.git] / src / pcap_sg.c
blob2db3ca18335fa7197f4f489931c71e973fae3429
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 <assert.h>
14 #include <unistd.h>
16 #include "pcap.h"
17 #include "xmalloc.h"
18 #include "xio.h"
19 #include "opt_memcpy.h"
20 #include "locking.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;
44 pcap_validate_header_maybe_die(&hdr);
46 return 0;
49 static int pcap_sg_push_file_header(int fd)
51 ssize_t ret;
52 struct pcap_filehdr hdr;
54 memset(&hdr, 0, sizeof(hdr));
55 pcap_prepare_header(&hdr, LINKTYPE_EN10MB, 0,
56 PCAP_DEFAULT_SNAPSHOT_LEN);
57 ret = write_or_die(fd, &hdr, sizeof(hdr));
58 if (unlikely(ret != sizeof(hdr))) {
59 whine("Failed to write pkt file header!\n");
60 return -EIO;
63 return 0;
66 static ssize_t pcap_sg_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
67 uint8_t *packet, size_t len)
69 ssize_t ret;
70 spinlock_lock(&lock);
71 if (unlikely(c == IOVSIZ)) {
72 ret = writev(fd, iov, IOVSIZ);
73 if (ret < 0)
74 panic("writev I/O error!\n");
75 c = 0;
77 iov[c].iov_len = 0;
78 __memcpy_small(iov[c].iov_base, hdr, sizeof(*hdr));
79 iov[c].iov_len += sizeof(*hdr);
80 __memcpy(iov[c].iov_base + iov[c].iov_len, packet, len);
81 iov[c].iov_len += len;
82 ret = iov[c].iov_len;
83 c++;
84 spinlock_unlock(&lock);
85 return ret;
88 static int pcap_sg_prepare_reading_pcap(int fd)
90 spinlock_lock(&lock);
91 avail = readv(fd, iov, IOVSIZ);
92 if (avail <= 0)
93 return -EIO;
94 used = iov_used = 0;
95 c = 0;
96 spinlock_unlock(&lock);
97 return 0;
100 static ssize_t pcap_sg_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
101 uint8_t *packet, size_t len)
103 /* In contrast to writing, reading gets really ugly ... */
104 spinlock_lock(&lock);
105 if (likely(avail - used >= sizeof(*hdr) &&
106 iov[c].iov_len - iov_used >= sizeof(*hdr))) {
107 __memcpy_small(hdr, iov[c].iov_base + iov_used, sizeof(*hdr));
108 iov_used += sizeof(*hdr);
109 used += sizeof(*hdr);
110 } else {
111 size_t remainder, offset = 0;
112 if (avail - used < sizeof(*hdr))
113 return -ENOMEM;
114 offset = iov[c].iov_len - iov_used;
115 remainder = sizeof(*hdr) - offset;
116 assert(offset + remainder == sizeof(*hdr));
117 __memcpy_small(hdr, iov[c].iov_base + iov_used, offset);
118 used += offset;
119 iov_used = 0;
120 c++;
121 if (c == IOVSIZ) {
122 /* We need to refetch! */
123 c = 0;
124 avail = readv(fd, iov, IOVSIZ);
125 if (avail < 0)
126 return -EIO;
127 used = 0;
129 /* Now we copy the remainder and go on with business ... */
130 __memcpy_small(hdr, iov[c].iov_base + iov_used, remainder);
131 iov_used += remainder;
132 used += remainder;
134 if (likely(avail - used >= hdr->len &&
135 iov[c].iov_len - iov_used >= hdr->len)) {
136 __memcpy(packet, iov[c].iov_base + iov_used, hdr->len);
137 iov_used += hdr->len;
138 used += hdr->len;
139 } else {
140 size_t remainder, offset = 0;
141 if (avail - used < hdr->len)
142 return -ENOMEM;
143 offset = iov[c].iov_len - iov_used;
144 remainder = hdr->len - offset;
145 assert(offset + remainder == hdr->len);
146 __memcpy(packet, iov[c].iov_base + iov_used, offset);
147 used += offset;
148 iov_used = 0;
149 c++;
150 if (c == IOVSIZ) {
151 /* We need to refetch! */
152 c = 0;
153 avail = readv(fd, iov, IOVSIZ);
154 if (avail < 0)
155 return -EIO;
156 used = 0;
158 /* Now we copy the remainder and go on with business ... */
159 __memcpy(packet, iov[c].iov_base + iov_used, remainder);
160 iov_used += remainder;
161 used += remainder;
163 spinlock_unlock(&lock);
164 if (unlikely(hdr->len == 0))
165 return -EINVAL; /* Bogus packet */
166 return sizeof(*hdr) + hdr->len;
169 static void pcap_sg_fsync_pcap(int fd)
171 ssize_t ret;
172 spinlock_lock(&lock);
173 ret = writev(fd, iov, c);
174 if (ret < 0)
175 panic("writev I/O error!\n");
176 c = 0;
177 fdatasync(fd);
178 spinlock_unlock(&lock);
181 struct pcap_file_ops pcap_sg_ops __read_mostly = {
182 .name = "SCATTER/GATHER",
183 .pull_file_header = pcap_sg_pull_file_header,
184 .push_file_header = pcap_sg_push_file_header,
185 .write_pcap_pkt = pcap_sg_write_pcap_pkt,
186 .prepare_reading_pcap = pcap_sg_prepare_reading_pcap,
187 .read_pcap_pkt = pcap_sg_read_pcap_pkt,
188 .fsync_pcap = pcap_sg_fsync_pcap,
191 int init_pcap_sg(int jumbo_support)
193 unsigned long i;
194 size_t allocsz = 0;
195 c = 0;
196 memset(iov, 0, sizeof(iov));
197 if (jumbo_support)
198 allocsz = ALLSIZ_JUMBO;
199 else
200 allocsz = ALLSIZ_2K;
201 for (i = 0; i < IOVSIZ; ++i) {
202 iov[i].iov_base = xmalloc_aligned(allocsz, 64);
203 iov[i].iov_len = allocsz;
205 spinlock_init(&lock);
206 return pcap_ops_group_register(&pcap_sg_ops, PCAP_OPS_SG);
209 void cleanup_pcap_sg(void)
211 unsigned long i;
212 spinlock_destroy(&lock);
213 for (i = 0; i < IOVSIZ; ++i)
214 xfree(iov[i].iov_base);
215 pcap_ops_group_unregister(PCAP_OPS_SG);