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 ret
= pcap_validate_header(&hdr
);
47 lseek(fd
, -sizeof(hdr
), SEEK_CUR
);
52 static int pcap_sg_push_file_header(int fd
)
55 struct pcap_filehdr hdr
;
57 fmemset(&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");
69 static int pcap_sg_prepare_writing_pcap(int fd
)
75 static ssize_t
pcap_sg_write_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
76 uint8_t *packet
, size_t len
)
82 if (unlikely(c
== IOVSIZ
)) {
83 ret
= writev(fd
, iov
, IOVSIZ
);
85 panic("writev I/O error!\n");
91 fmemcpy(iov
[c
].iov_base
, hdr
, sizeof(*hdr
));
93 iov
[c
].iov_len
+= sizeof(*hdr
);
94 fmemcpy(iov
[c
].iov_base
+ iov
[c
].iov_len
, packet
, len
);
96 iov
[c
].iov_len
+= len
;
101 spinlock_unlock(&lock
);
106 static int pcap_sg_prepare_reading_pcap(int fd
)
110 spinlock_lock(&lock
);
112 avail
= readv(fd
, iov
, IOVSIZ
);
119 spinlock_unlock(&lock
);
124 static ssize_t
pcap_sg_read_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
125 uint8_t *packet
, size_t len
)
127 /* In contrast to writing, reading gets really ugly ... */
128 spinlock_lock(&lock
);
130 if (likely(avail
- used
>= sizeof(*hdr
) &&
131 iov
[c
].iov_len
- iov_used
>= sizeof(*hdr
))) {
133 fmemcpy(hdr
, iov
[c
].iov_base
+ iov_used
, sizeof(*hdr
));
134 iov_used
+= sizeof(*hdr
);
136 used
+= sizeof(*hdr
);
139 size_t remainder
, offset
= 0;
141 if (avail
- used
< sizeof(*hdr
))
144 offset
= iov
[c
].iov_len
- iov_used
;
145 remainder
= sizeof(*hdr
) - offset
;
147 bug_on(offset
+ remainder
!= sizeof(*hdr
));
149 fmemcpy(hdr
, iov
[c
].iov_base
+ iov_used
, offset
);
156 /* We need to refetch! */
159 avail
= readv(fd
, iov
, IOVSIZ
);
166 /* Now we copy the remainder and go on with business ... */
167 fmemcpy(hdr
, iov
[c
].iov_base
+ iov_used
, remainder
);
168 iov_used
+= remainder
;
172 if (likely(avail
- used
>= hdr
->len
&&
173 iov
[c
].iov_len
- iov_used
>= hdr
->len
)) {
175 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, hdr
->len
);
176 iov_used
+= hdr
->len
;
181 size_t remainder
, offset
= 0;
183 if (avail
- used
< hdr
->len
)
186 offset
= iov
[c
].iov_len
- iov_used
;
187 remainder
= hdr
->len
- offset
;
189 bug_on(offset
+ remainder
!= hdr
->len
);
191 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, offset
);
198 /* We need to refetch! */
201 avail
= readv(fd
, iov
, IOVSIZ
);
208 /* Now we copy the remainder and go on with business ... */
209 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, remainder
);
210 iov_used
+= remainder
;
215 spinlock_unlock(&lock
);
217 if (unlikely(hdr
->len
== 0))
218 return -EINVAL
; /* Bogus packet */
220 return sizeof(*hdr
) + hdr
->len
;
223 static void pcap_sg_fsync_pcap(int fd
)
227 spinlock_lock(&lock
);
229 ret
= writev(fd
, iov
, c
);
231 panic("writev I/O error!\n");
237 spinlock_unlock(&lock
);
240 struct pcap_file_ops pcap_sg_ops __read_mostly
= {
241 .name
= "scatter-gather",
242 .pull_file_header
= pcap_sg_pull_file_header
,
243 .push_file_header
= pcap_sg_push_file_header
,
244 .write_pcap_pkt
= pcap_sg_write_pcap_pkt
,
245 .prepare_reading_pcap
= pcap_sg_prepare_reading_pcap
,
246 .prepare_writing_pcap
= pcap_sg_prepare_writing_pcap
,
247 .read_pcap_pkt
= pcap_sg_read_pcap_pkt
,
248 .fsync_pcap
= pcap_sg_fsync_pcap
,
251 int init_pcap_sg(int jumbo_support
)
258 fmemset(iov
, 0, sizeof(iov
));
261 allocsz
= ALLSIZ_JUMBO
;
265 for (i
= 0; i
< IOVSIZ
; ++i
) {
266 iov
[i
].iov_base
= xmalloc_aligned(allocsz
, 64);
267 iov
[i
].iov_len
= allocsz
;
270 spinlock_init(&lock
);
272 return pcap_ops_group_register(&pcap_sg_ops
, PCAP_OPS_SG
);
275 void cleanup_pcap_sg(void)
279 spinlock_destroy(&lock
);
281 for (i
= 0; i
< IOVSIZ
; ++i
)
282 xfree(iov
[i
].iov_base
);
284 pcap_ops_group_unregister(PCAP_OPS_SG
);