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.
22 #define PAGE_SIZE (getpagesize())
23 #define PAGE_MASK (~(PAGE_SIZE - 1))
24 #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
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
)
39 struct pcap_filehdr hdr
;
41 ret
= read(fd
, &hdr
, sizeof(hdr
));
42 if (unlikely(ret
!= sizeof(hdr
)))
45 pcap_validate_header(&hdr
);
50 static int pcap_sg_push_file_header(int fd
)
53 struct pcap_filehdr hdr
;
55 fmemset(&hdr
, 0, sizeof(hdr
));
56 pcap_prepare_header(&hdr
, LINKTYPE_EN10MB
, 0,
57 PCAP_DEFAULT_SNAPSHOT_LEN
);
58 ret
= write_or_die(fd
, &hdr
, sizeof(hdr
));
59 if (unlikely(ret
!= sizeof(hdr
))) {
60 whine("Failed to write pkt file header!\n");
67 static int pcap_sg_prepare_writing_pcap(int fd
)
73 static ssize_t
pcap_sg_write_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
74 uint8_t *packet
, size_t len
)
80 if (unlikely(c
== IOVSIZ
)) {
81 ret
= writev(fd
, iov
, IOVSIZ
);
83 panic("writev I/O error!\n");
89 fmemcpy(iov
[c
].iov_base
, hdr
, sizeof(*hdr
));
91 iov
[c
].iov_len
+= sizeof(*hdr
);
92 fmemcpy(iov
[c
].iov_base
+ iov
[c
].iov_len
, packet
, len
);
94 iov
[c
].iov_len
+= len
;
99 spinlock_unlock(&lock
);
104 static int pcap_sg_prepare_reading_pcap(int fd
)
108 spinlock_lock(&lock
);
109 avail
= readv(fd
, iov
, IOVSIZ
);
115 spinlock_unlock(&lock
);
120 static ssize_t
pcap_sg_read_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
121 uint8_t *packet
, size_t len
)
125 /* In contrast to writing, reading gets really ugly ... */
126 spinlock_lock(&lock
);
128 if (likely(avail
- used
>= sizeof(*hdr
) &&
129 iov
[c
].iov_len
- iov_used
>= sizeof(*hdr
))) {
131 fmemcpy(hdr
, iov
[c
].iov_base
+ iov_used
, sizeof(*hdr
));
132 iov_used
+= sizeof(*hdr
);
133 used
+= sizeof(*hdr
);
135 size_t remainder
, offset
= 0;
137 if (avail
- used
< sizeof(*hdr
)) {
142 offset
= iov
[c
].iov_len
- iov_used
;
143 remainder
= sizeof(*hdr
) - offset
;
145 bug_on(offset
+ remainder
!= sizeof(*hdr
));
147 fmemcpy(hdr
, iov
[c
].iov_base
+ iov_used
, offset
);
153 /* We need to refetch! */
155 avail
= readv(fd
, iov
, IOVSIZ
);
163 /* Now we copy the remainder and go on with business ... */
164 fmemcpy((uint8_t *) hdr
/*+ offset*/,
165 iov
[c
].iov_base
+ iov_used
, remainder
);
166 iov_used
+= remainder
;
170 if (unlikely(hdr
->len
== 0 || hdr
->len
> len
)) {
171 ret
= -EINVAL
; /* Bogus packet */
175 if (likely(avail
- used
>= hdr
->len
&&
176 iov
[c
].iov_len
- iov_used
>= hdr
->len
)) {
178 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, hdr
->len
);
179 iov_used
+= hdr
->len
;
182 size_t remainder
, offset
= 0;
184 if (avail
- used
< hdr
->len
) {
189 offset
= iov
[c
].iov_len
- iov_used
;
190 remainder
= hdr
->len
- offset
;
192 bug_on(offset
+ remainder
!= hdr
->len
);
194 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, offset
);
200 /* We need to refetch! */
202 avail
= readv(fd
, iov
, IOVSIZ
);
210 /* Now we copy the remainder and go on with business ... */
211 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, remainder
);
212 iov_used
+= remainder
;
216 spinlock_unlock(&lock
);
218 return sizeof(*hdr
) + hdr
->len
;
221 spinlock_unlock(&lock
);
225 static void pcap_sg_fsync_pcap(int fd
)
229 spinlock_lock(&lock
);
231 ret
= writev(fd
, iov
, c
);
233 panic("writev I/O error!\n");
239 spinlock_unlock(&lock
);
242 struct pcap_file_ops pcap_sg_ops __read_mostly
= {
243 .name
= "scatter-gather",
244 .pull_file_header
= pcap_sg_pull_file_header
,
245 .push_file_header
= pcap_sg_push_file_header
,
246 .write_pcap_pkt
= pcap_sg_write_pcap_pkt
,
247 .prepare_reading_pcap
= pcap_sg_prepare_reading_pcap
,
248 .prepare_writing_pcap
= pcap_sg_prepare_writing_pcap
,
249 .read_pcap_pkt
= pcap_sg_read_pcap_pkt
,
250 .fsync_pcap
= pcap_sg_fsync_pcap
,
253 int init_pcap_sg(int jumbo_support
)
260 fmemset(iov
, 0, sizeof(iov
));
263 allocsz
= ALLSIZ_JUMBO
;
267 for (i
= 0; i
< IOVSIZ
; ++i
) {
268 iov
[i
].iov_base
= xmalloc_aligned(allocsz
, 64);
269 iov
[i
].iov_len
= allocsz
;
272 spinlock_init(&lock
);
274 return pcap_ops_group_register(&pcap_sg_ops
, PCAP_OPS_SG
);
277 void cleanup_pcap_sg(void)
281 spinlock_destroy(&lock
);
283 for (i
= 0; i
< IOVSIZ
; ++i
)
284 xfree(iov
[i
].iov_base
);
286 pcap_ops_group_unregister(PCAP_OPS_SG
);