xio: add comment to function
[netsniff-ng.git] / pcap_sg.c
blob620e072461a84d430fc8dc1e08ab0d5b1ea4d001
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;
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 iov[iov_slot].iov_len = 0;
38 switch (type) {
39 #define PCAP_HDR_WRITE(__member__) do { \
40 fmemcpy(iov[iov_slot].iov_base, &phdr->__member__, \
41 sizeof(phdr->__member__)); \
42 iov[iov_slot].iov_len += sizeof(phdr->__member__); \
43 } while(0)
44 #define CASE_HDR_WRITE(what, member) \
45 case (what): \
46 PCAP_HDR_WRITE(member); \
47 break
48 CASE_HDR_WRITE(DEFAULT, ppo);
49 CASE_HDR_WRITE(NSEC, ppn);
50 CASE_HDR_WRITE(KUZNETZOV, ppk);
51 CASE_HDR_WRITE(BORKMANN, ppb);
52 default:
53 bug();
56 fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
57 ret = (iov[iov_slot].iov_len += len);
58 iov_slot++;
60 return ret;
63 static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
64 uint8_t *packet, size_t len, size_t hdrsize)
66 int ret;
67 size_t offset = 0;
68 ssize_t remainder;
70 offset = iov[iov_slot].iov_len - iov_off_rd;
71 remainder = hdrsize - offset;
72 if (remainder < 0)
73 remainder = 0;
75 bug_on(offset + remainder != hdrsize);
77 switch (type) {
78 #define CASE_HDR_PREAD(what, __member__) \
79 case (what): \
80 fmemcpy(&phdr->__member__, \
81 iov[iov_slot].iov_base + iov_off_rd, offset); \
82 break
83 CASE_HDR_PREAD(DEFAULT, ppo);
84 CASE_HDR_PREAD(NSEC, ppn);
85 CASE_HDR_PREAD(KUZNETZOV, ppk);
86 CASE_HDR_PREAD(BORKMANN, ppb);
87 default:
88 bug();
91 iov_off_rd = 0;
92 iov_slot++;
94 if (iov_slot == array_size(iov)) {
95 iov_slot = 0;
96 ret = readv(fd, iov, array_size(iov));
97 if (unlikely(ret <= 0))
98 return -EIO;
101 switch (type) {
102 #define CASE_HDR_RREAD(what, __member__) \
103 case (what): \
104 fmemcpy(&phdr->__member__ + offset, \
105 iov[iov_slot].iov_base + iov_off_rd, remainder); \
106 break
107 CASE_HDR_RREAD(DEFAULT, ppo);
108 CASE_HDR_RREAD(NSEC, ppn);
109 CASE_HDR_RREAD(KUZNETZOV, ppk);
110 CASE_HDR_RREAD(BORKMANN, ppb);
111 default:
112 bug();
115 iov_off_rd += remainder;
117 return hdrsize;
120 static ssize_t __pcap_sg_inter_iov_data_read(int fd, uint8_t *packet, size_t len, size_t hdrlen)
122 int ret;
123 size_t offset = 0;
124 ssize_t remainder;
126 offset = iov[iov_slot].iov_len - iov_off_rd;
127 remainder = hdrlen - offset;
128 if (remainder < 0)
129 remainder = 0;
131 bug_on(offset + remainder != hdrlen);
133 fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, offset);
134 iov_off_rd = 0;
135 iov_slot++;
137 if (iov_slot == array_size(iov)) {
138 iov_slot = 0;
139 ret = readv(fd, iov, array_size(iov));
140 if (unlikely(ret <= 0))
141 return -EIO;
144 fmemcpy(packet + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
145 iov_off_rd += remainder;
147 return hdrlen;
150 static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
151 uint8_t *packet, size_t len)
153 ssize_t ret = 0;
154 size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
156 if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrsize)) {
157 switch (type) {
158 #define CASE_HDR_READ(what, __member__) \
159 case (what): \
160 fmemcpy(&phdr->__member__, \
161 iov[iov_slot].iov_base + iov_off_rd, hdrsize); \
162 break
163 CASE_HDR_READ(DEFAULT, ppo);
164 CASE_HDR_READ(NSEC, ppn);
165 CASE_HDR_READ(KUZNETZOV, ppk);
166 CASE_HDR_READ(BORKMANN, ppb);
167 default:
168 bug();
171 iov_off_rd += hdrsize;
172 } else {
173 ret = __pcap_sg_inter_iov_hdr_read(fd, phdr, type, packet,
174 len, hdrsize);
175 if (unlikely(ret < 0))
176 return ret;
179 hdrlen = pcap_get_length(phdr, type);
180 if (unlikely(hdrlen == 0 || hdrlen > len))
181 return -EINVAL;
183 if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrlen)) {
184 fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, hdrlen);
185 iov_off_rd += hdrlen;
186 } else {
187 ret = __pcap_sg_inter_iov_data_read(fd, packet, len, hdrlen);
188 if (unlikely(ret < 0))
189 return ret;
192 return hdrsize + hdrlen;
195 static void pcap_sg_fsync(int fd)
197 ssize_t ret = writev(fd, iov, iov_slot);
198 if (ret < 0)
199 panic("Writev I/O error: %s!\n", strerror(errno));
201 iov_slot = 0;
202 fdatasync(fd);
205 static int pcap_sg_prepare_access(int fd, enum pcap_mode mode, bool jumbo)
207 int i, ret;
208 size_t len = 0;
210 iov_slot = 0;
211 len = jumbo ? (PAGE_SIZE * 16) /* 64k max */ :
212 (PAGE_SIZE * 3) /* 12k max */;
214 for (i = 0; i < array_size(iov); ++i) {
215 iov[i].iov_base = xzmalloc_aligned(len, 64);
216 iov[i].iov_len = len;
219 set_ioprio_rt();
221 if (mode == PCAP_MODE_RD) {
222 ret = readv(fd, iov, array_size(iov));
223 if (ret <= 0)
224 return -EIO;
226 iov_off_rd = 0;
227 iov_slot = 0;
230 return 0;
233 static void pcap_sg_prepare_close(int fd, enum pcap_mode mode)
235 int i;
237 for (i = 0; i < array_size(iov); ++i)
238 xfree(iov[i].iov_base);
241 const struct pcap_file_ops pcap_sg_ops = {
242 .pull_fhdr_pcap = pcap_generic_pull_fhdr,
243 .push_fhdr_pcap = pcap_generic_push_fhdr,
244 .prepare_access_pcap = pcap_sg_prepare_access,
245 .prepare_close_pcap = pcap_sg_prepare_close,
246 .read_pcap = pcap_sg_read,
247 .write_pcap = pcap_sg_write,
248 .fsync_pcap = pcap_sg_fsync,