mmap: let grow area less intense
[netsniff-ng-old.git] / src / pcap_mmap.c
blob5017d5c8749280fb0e84c70dfcd224ca98ddd88f
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 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <sys/mman.h>
16 #include "pcap.h"
17 #include "xio.h"
18 #include "xsys.h"
19 #include "locking.h"
20 #include "built_in.h"
22 #define DEFAULT_SLOTS 1000
24 #define PAGE_SIZE (getpagesize())
25 #define PAGE_MASK (~(PAGE_SIZE - 1))
26 #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
28 static struct spinlock lock;
29 static off_t map_size = 0;
30 static char *pstart, *pcurr;
31 static int jumbo_frames = 0;
33 static inline off_t get_map_size(void)
35 int allocsz = jumbo_frames ? 16 : 3;
36 return PAGE_ALIGN(sizeof(struct pcap_filehdr) +
37 (PAGE_SIZE * allocsz) * DEFAULT_SLOTS);
40 static int pcap_mmap_pull_file_header(int fd, uint32_t *linktype)
42 ssize_t ret;
43 struct pcap_filehdr hdr;
45 ret = read(fd, &hdr, sizeof(hdr));
46 if (unlikely(ret != sizeof(hdr)))
47 return -EIO;
49 pcap_validate_header(&hdr);
51 *linktype = hdr.linktype;
53 return 0;
56 static int pcap_mmap_push_file_header(int fd, uint32_t linktype)
58 ssize_t ret;
59 struct pcap_filehdr hdr;
61 fmemset(&hdr, 0, sizeof(hdr));
62 pcap_prepare_header(&hdr, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN);
64 ret = write_or_die(fd, &hdr, sizeof(hdr));
65 if (unlikely(ret != sizeof(hdr))) {
66 whine("Failed to write pkt file header!\n");
67 return -EIO;
70 return 0;
73 static int pcap_mmap_prepare_writing_pcap(int fd)
75 int ret;
76 off_t pos;
77 struct stat sb;
79 set_ioprio_be();
81 spinlock_lock(&lock);
83 map_size = get_map_size();
85 ret = fstat(fd, &sb);
86 if (ret < 0)
87 panic("Cannot fstat pcap file!\n");
88 if (!S_ISREG (sb.st_mode))
89 panic("pcap dump file is not a regular file!\n");
91 pos = lseek(fd, map_size, SEEK_SET);
92 if (pos < 0)
93 panic("Cannot lseek pcap file!\n");
95 ret = write_or_die(fd, "", 1);
96 if (ret != 1)
97 panic("Cannot write file!\n");
99 pstart = mmap(0, map_size, PROT_WRITE, MAP_SHARED
100 /*| MAP_HUGETLB*/, fd, 0);
101 if (pstart == MAP_FAILED)
102 panic("mmap of file failed!");
104 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
105 if (ret < 0)
106 panic("Failed to give kernel mmap advise!\n");
108 pcurr = pstart + sizeof(struct pcap_filehdr);
110 spinlock_unlock(&lock);
112 return 0;
115 static ssize_t pcap_mmap_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
116 uint8_t *packet, size_t len)
118 int ret;
119 off_t pos;
121 spinlock_lock(&lock);
123 if ((off_t) (pcurr - pstart) + sizeof(*hdr) + len > map_size) {
124 off_t map_size_old = map_size;
125 off_t offset = (pcurr - pstart);
127 map_size = PAGE_ALIGN(map_size_old * 10 / 8);
129 pos = lseek(fd, map_size, SEEK_SET);
130 if (pos < 0)
131 panic("Cannot lseek pcap file!\n");
133 ret = write_or_die(fd, "", 1);
134 if (ret != 1)
135 panic("Cannot write file!\n");
137 pstart = mremap(pstart, map_size_old, map_size, MREMAP_MAYMOVE);
138 if (pstart == MAP_FAILED)
139 panic("mmap of file failed!");
141 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
142 if (ret < 0)
143 panic("Failed to give kernel mmap advise!\n");
145 pcurr = pstart + offset;
148 fmemcpy(pcurr, hdr, sizeof(*hdr));
149 pcurr += sizeof(*hdr);
151 fmemcpy(pcurr, packet, len);
152 pcurr += len;
154 spinlock_unlock(&lock);
156 return sizeof(*hdr) + len;
159 static int pcap_mmap_prepare_reading_pcap(int fd)
161 int ret;
162 struct stat sb;
164 set_ioprio_be();
166 spinlock_lock(&lock);
168 ret = fstat(fd, &sb);
169 if (ret < 0)
170 panic("Cannot fstat pcap file!\n");
172 if (!S_ISREG (sb.st_mode))
173 panic("pcap dump file is not a regular file!\n");
175 map_size = sb.st_size;
177 pstart = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED
178 /*| MAP_HUGETLB*/, fd, 0);
179 if (pstart == MAP_FAILED)
180 panic("mmap of file failed!");
182 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
183 if (ret < 0)
184 panic("Failed to give kernel mmap advise!\n");
186 pcurr = pstart + sizeof(struct pcap_filehdr);
188 spinlock_unlock(&lock);
190 return 0;
193 static ssize_t pcap_mmap_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
194 uint8_t *packet, size_t len)
196 ssize_t ret;
197 spinlock_lock(&lock);
199 if (unlikely((off_t) (pcurr + sizeof(*hdr) - pstart) > map_size)) {
200 spinlock_unlock(&lock);
201 return -ENOMEM;
204 fmemcpy(hdr, pcurr, sizeof(*hdr));
205 pcurr += sizeof(*hdr);
207 if (unlikely((off_t) (pcurr + hdr->caplen - pstart) > map_size)) {
208 ret = -ENOMEM;
209 goto out_err;
212 if (unlikely(hdr->caplen == 0 || hdr->caplen > len)) {
213 ret = -EINVAL; /* Bogus packet */
214 goto out_err;
217 fmemcpy(packet, pcurr, hdr->caplen);
218 pcurr += hdr->caplen;
220 spinlock_unlock(&lock);
222 return sizeof(*hdr) + hdr->caplen;
224 out_err:
225 spinlock_unlock(&lock);
226 return ret;
229 static void pcap_mmap_fsync_pcap(int fd)
231 spinlock_lock(&lock);
233 msync(pstart, (off_t) (pcurr - pstart), MS_ASYNC);
235 spinlock_unlock(&lock);
238 static void pcap_mmap_prepare_close_pcap(int fd, enum pcap_mode mode)
240 spinlock_lock(&lock);
242 int ret = munmap(pstart, map_size);
243 if (ret < 0)
244 panic("Cannot unmap the pcap file!\n");
246 if (mode == PCAP_MODE_WRITE) {
247 ret = ftruncate(fd, (off_t) (pcurr - pstart));
248 if (ret)
249 panic("Cannot truncate the pcap file!\n");
252 spinlock_unlock(&lock);
255 struct pcap_file_ops pcap_mmap_ops __read_mostly = {
256 .name = "mmap",
257 .pull_file_header = pcap_mmap_pull_file_header,
258 .push_file_header = pcap_mmap_push_file_header,
259 .prepare_writing_pcap = pcap_mmap_prepare_writing_pcap,
260 .write_pcap_pkt = pcap_mmap_write_pcap_pkt,
261 .prepare_reading_pcap = pcap_mmap_prepare_reading_pcap,
262 .read_pcap_pkt = pcap_mmap_read_pcap_pkt,
263 .fsync_pcap = pcap_mmap_fsync_pcap,
264 .prepare_close_pcap = pcap_mmap_prepare_close_pcap,
267 int init_pcap_mmap(int jumbo_support)
269 spinlock_init(&lock);
271 jumbo_frames = jumbo_support;
273 return pcap_ops_group_register(&pcap_mmap_ops, PCAP_OPS_MMAP);
276 void cleanup_pcap_mmap(void)
278 spinlock_destroy(&lock);
280 pcap_ops_group_unregister(PCAP_OPS_MMAP);