docs: Added note to curvetun doc
[netsniff-ng.git] / src / pcap_mmap.c
blob72a96c168ad8a7d53697aeef6901894a14062694
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 "opt_memcpy.h"
19 #include "locking.h"
21 #define DEFAULT_SLOTS 1000
23 #define PAGE_SIZE (getpagesize())
24 #define PAGE_MASK (~(PAGE_SIZE - 1))
25 #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
27 static struct spinlock lock;
28 static off_t map_size = 0;
29 static char *pstart, *pcurr;
30 static int jumbo_frames = 0;
32 static inline off_t get_map_size(void)
34 int allocsz = jumbo_frames ? 16 : 3;
35 return PAGE_ALIGN(sizeof(struct pcap_filehdr) +
36 (PAGE_SIZE * allocsz) * DEFAULT_SLOTS);
39 static int pcap_mmap_pull_file_header(int fd)
41 ssize_t ret;
42 struct pcap_filehdr hdr;
44 ret = read(fd, &hdr, sizeof(hdr));
45 if (unlikely(ret != sizeof(hdr)))
46 return -EIO;
47 pcap_validate_header_maybe_die(&hdr);
49 return 0;
52 static int pcap_mmap_push_file_header(int fd)
54 ssize_t ret;
55 struct pcap_filehdr hdr;
57 memset(&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_mmap_prepare_writing_pcap(int fd)
71 int ret;
72 struct stat sb;
74 spinlock_lock(&lock);
75 map_size = get_map_size();
76 ret = fstat(fd, &sb);
77 if (ret < 0)
78 panic("Cannot fstat pcap file!\n");
79 if (!S_ISREG (sb.st_mode))
80 panic("pcap dump file is not a regular file!\n");
81 /* Expand file buffer, so that mmap can be done. */
82 ret = lseek(fd, map_size, SEEK_SET);
83 if (ret < 0)
84 panic("Cannot lseek pcap file!\n");
85 ret = write_or_die(fd, "", 1);
86 if (ret != 1)
87 panic("Cannot write file!\n");
88 pstart = mmap(0, map_size, PROT_WRITE, MAP_SHARED
89 /*| MAP_HUGETLB*/, fd, 0);
90 if (pstart == MAP_FAILED)
91 panic("mmap of file failed!");
92 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
93 if (ret < 0)
94 panic("Failed to give kernel mmap advise!\n");
95 pcurr = pstart + sizeof(struct pcap_filehdr);
96 spinlock_unlock(&lock);
98 return 0;
101 static ssize_t pcap_mmap_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
102 uint8_t *packet, size_t len)
104 int ret;
106 spinlock_lock(&lock);
107 if ((off_t) (pcurr - pstart) + sizeof(*hdr) + len > map_size) {
108 off_t map_size_old = map_size;
109 off_t offset = (pcurr - pstart);
110 map_size = PAGE_ALIGN(map_size_old * 3 / 2);
111 ret = lseek(fd, map_size, SEEK_SET);
112 if (ret < 0)
113 panic("Cannot lseek pcap file!\n");
114 ret = write_or_die(fd, "", 1);
115 if (ret != 1)
116 panic("Cannot write file!\n");
117 pstart = mremap(pstart, map_size_old, map_size, MREMAP_MAYMOVE);
118 if (pstart == MAP_FAILED)
119 panic("mmap of file failed!");
120 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
121 if (ret < 0)
122 panic("Failed to give kernel mmap advise!\n");
123 pcurr = pstart + offset;
125 __memcpy_small(pcurr, hdr, sizeof(*hdr));
126 pcurr += sizeof(*hdr);
127 __memcpy(pcurr, packet, len);
128 pcurr += len;
129 spinlock_unlock(&lock);
131 return sizeof(*hdr) + len;
134 static int pcap_mmap_prepare_reading_pcap(int fd)
136 int ret;
137 struct stat sb;
139 spinlock_lock(&lock);
140 ret = fstat(fd, &sb);
141 if (ret < 0)
142 panic("Cannot fstat pcap file!\n");
143 if (!S_ISREG (sb.st_mode))
144 panic("pcap dump file is not a regular file!\n");
145 map_size = sb.st_size;
146 pstart = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED
147 /*| MAP_HUGETLB*/, fd, 0);
148 if (pstart == MAP_FAILED)
149 panic("mmap of file failed!");
150 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
151 if (ret < 0)
152 panic("Failed to give kernel mmap advise!\n");
153 pcurr = pstart + sizeof(struct pcap_filehdr);
154 spinlock_unlock(&lock);
156 return 0;
159 static ssize_t pcap_mmap_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
160 uint8_t *packet, size_t len)
162 spinlock_lock(&lock);
163 if (unlikely((off_t) (pcurr + sizeof(*hdr) - pstart) > map_size)) {
164 spinlock_unlock(&lock);
165 return -ENOMEM;
167 __memcpy_small(hdr, pcurr, sizeof(*hdr));
168 pcurr += sizeof(*hdr);
169 if (unlikely((off_t) (pcurr + hdr->len - pstart) > map_size)) {
170 spinlock_unlock(&lock);
171 return -ENOMEM;
173 __memcpy(packet, pcurr, hdr->len);
174 pcurr += hdr->len;
175 spinlock_unlock(&lock);
177 if (unlikely(hdr->len == 0))
178 return -EINVAL; /* Bogus packet */
179 return sizeof(*hdr) + hdr->len;
182 static void pcap_mmap_fsync_pcap(int fd)
184 spinlock_lock(&lock);
185 msync(pstart, (off_t) (pcurr - pstart), MS_ASYNC);
186 spinlock_unlock(&lock);
189 static void pcap_mmap_prepare_close_pcap(int fd, enum pcap_mode mode)
191 spinlock_lock(&lock);
192 int ret = munmap(pstart, map_size);
193 if (ret < 0)
194 panic("Cannot unmap the pcap file!\n");
195 if (mode == PCAP_MODE_WRITE) {
196 ret = ftruncate(fd, (off_t) (pcurr - pstart));
197 if (ret)
198 panic("Cannot truncate the pcap file!\n");
200 spinlock_unlock(&lock);
203 struct pcap_file_ops pcap_mmap_ops __read_mostly = {
204 .name = "MMAP",
205 .pull_file_header = pcap_mmap_pull_file_header,
206 .push_file_header = pcap_mmap_push_file_header,
207 .prepare_writing_pcap = pcap_mmap_prepare_writing_pcap,
208 .write_pcap_pkt = pcap_mmap_write_pcap_pkt,
209 .prepare_reading_pcap = pcap_mmap_prepare_reading_pcap,
210 .read_pcap_pkt = pcap_mmap_read_pcap_pkt,
211 .fsync_pcap = pcap_mmap_fsync_pcap,
212 .prepare_close_pcap = pcap_mmap_prepare_close_pcap,
215 int init_pcap_mmap(int jumbo_support)
217 spinlock_init(&lock);
218 jumbo_frames = jumbo_support;
219 return pcap_ops_group_register(&pcap_mmap_ops, PCAP_OPS_MMAP);
222 void cleanup_pcap_mmap(void)
224 spinlock_destroy(&lock);
225 pcap_ops_group_unregister(PCAP_OPS_MMAP);