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.
19 #include "opt_memcpy.h"
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
)))
44 pcap_validate_header_maybe_die(&hdr
);
49 static int pcap_sg_push_file_header(int fd
)
52 struct pcap_filehdr hdr
;
54 memset(&hdr
, 0, sizeof(hdr
));
55 pcap_prepare_header(&hdr
, LINKTYPE_EN10MB
, 0,
56 PCAP_DEFAULT_SNAPSHOT_LEN
);
57 ret
= write_or_die(fd
, &hdr
, sizeof(hdr
));
58 if (unlikely(ret
!= sizeof(hdr
))) {
59 whine("Failed to write pkt file header!\n");
66 static ssize_t
pcap_sg_write_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
67 uint8_t *packet
, size_t len
)
71 if (unlikely(c
== IOVSIZ
)) {
72 ret
= writev(fd
, iov
, IOVSIZ
);
74 panic("writev I/O error!\n");
78 __memcpy_small(iov
[c
].iov_base
, hdr
, sizeof(*hdr
));
79 iov
[c
].iov_len
+= sizeof(*hdr
);
80 __memcpy(iov
[c
].iov_base
+ iov
[c
].iov_len
, packet
, len
);
81 iov
[c
].iov_len
+= len
;
84 spinlock_unlock(&lock
);
88 static int pcap_sg_prepare_reading_pcap(int fd
)
91 avail
= readv(fd
, iov
, IOVSIZ
);
96 spinlock_unlock(&lock
);
100 static ssize_t
pcap_sg_read_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
101 uint8_t *packet
, size_t len
)
103 /* In contrast to writing, reading gets really ugly ... */
104 spinlock_lock(&lock
);
105 if (likely(avail
- used
>= sizeof(*hdr
) &&
106 iov
[c
].iov_len
- iov_used
>= sizeof(*hdr
))) {
107 __memcpy_small(hdr
, iov
[c
].iov_base
+ iov_used
, sizeof(*hdr
));
108 iov_used
+= sizeof(*hdr
);
109 used
+= sizeof(*hdr
);
111 size_t remainder
, offset
= 0;
112 if (avail
- used
< sizeof(*hdr
))
114 offset
= iov
[c
].iov_len
- iov_used
;
115 remainder
= sizeof(*hdr
) - offset
;
116 assert(offset
+ remainder
== sizeof(*hdr
));
117 __memcpy_small(hdr
, iov
[c
].iov_base
+ iov_used
, offset
);
122 /* We need to refetch! */
124 avail
= readv(fd
, iov
, IOVSIZ
);
129 /* Now we copy the remainder and go on with business ... */
130 __memcpy_small(hdr
, iov
[c
].iov_base
+ iov_used
, remainder
);
131 iov_used
+= remainder
;
134 if (likely(avail
- used
>= hdr
->len
&&
135 iov
[c
].iov_len
- iov_used
>= hdr
->len
)) {
136 __memcpy(packet
, iov
[c
].iov_base
+ iov_used
, hdr
->len
);
137 iov_used
+= hdr
->len
;
140 size_t remainder
, offset
= 0;
141 if (avail
- used
< hdr
->len
)
143 offset
= iov
[c
].iov_len
- iov_used
;
144 remainder
= hdr
->len
- offset
;
145 assert(offset
+ remainder
== hdr
->len
);
146 __memcpy(packet
, iov
[c
].iov_base
+ iov_used
, offset
);
151 /* We need to refetch! */
153 avail
= readv(fd
, iov
, IOVSIZ
);
158 /* Now we copy the remainder and go on with business ... */
159 __memcpy(packet
, iov
[c
].iov_base
+ iov_used
, remainder
);
160 iov_used
+= remainder
;
163 spinlock_unlock(&lock
);
164 if (unlikely(hdr
->len
== 0))
165 return -EINVAL
; /* Bogus packet */
166 return sizeof(*hdr
) + hdr
->len
;
169 static void pcap_sg_fsync_pcap(int fd
)
172 spinlock_lock(&lock
);
173 ret
= writev(fd
, iov
, c
);
175 panic("writev I/O error!\n");
178 spinlock_unlock(&lock
);
181 struct pcap_file_ops pcap_sg_ops __read_mostly
= {
182 .name
= "SCATTER/GATHER",
183 .pull_file_header
= pcap_sg_pull_file_header
,
184 .push_file_header
= pcap_sg_push_file_header
,
185 .write_pcap_pkt
= pcap_sg_write_pcap_pkt
,
186 .prepare_reading_pcap
= pcap_sg_prepare_reading_pcap
,
187 .read_pcap_pkt
= pcap_sg_read_pcap_pkt
,
188 .fsync_pcap
= pcap_sg_fsync_pcap
,
191 int init_pcap_sg(int jumbo_support
)
196 memset(iov
, 0, sizeof(iov
));
198 allocsz
= ALLSIZ_JUMBO
;
201 for (i
= 0; i
< IOVSIZ
; ++i
) {
202 iov
[i
].iov_base
= xmalloc_aligned(allocsz
, 64);
203 iov
[i
].iov_len
= allocsz
;
205 spinlock_init(&lock
);
206 return pcap_ops_group_register(&pcap_sg_ops
, PCAP_OPS_SG
);
209 void cleanup_pcap_sg(void)
212 spinlock_destroy(&lock
);
213 for (i
= 0; i
< IOVSIZ
; ++i
)
214 xfree(iov
[i
].iov_base
);
215 pcap_ops_group_unregister(PCAP_OPS_SG
);