Revert thread changes before branching
[netsniff-ng.git] / netsniff-ng / lib / rx_ring.c
blob36170656d92ce9e748bc4decc6a08b069b0b1b7f
1 /*
2 * Copyright (C) 2009, 2010 Daniel Borkmann <daniel@netsniff-ng.org> and
3 * Emmanuel Roullit <emmanuel@netsniff-ng.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
20 #define _GNU_SOURCE
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <unistd.h>
31 #include <pthread.h>
33 #include <net/if.h>
34 #include <arpa/inet.h>
36 #include <sys/ioctl.h>
37 #include <sys/mman.h>
38 #include <sys/poll.h>
39 #include <sys/types.h>
41 #include <linux/if_ether.h>
42 #include <linux/if_packet.h>
43 #include <linux/filter.h>
45 #include <netsniff-ng/pcap.h>
46 #include <netsniff-ng/cursor.h>
47 #include <netsniff-ng/dump.h>
48 #include <netsniff-ng/macros.h>
49 #include <netsniff-ng/types.h>
50 #include <netsniff-ng/rx_ring.h>
51 #include <netsniff-ng/netdev.h>
52 #include <netsniff-ng/config.h>
53 #include <netsniff-ng/signal.h>
55 /**
56 * destroy_virt_rx_ring - Destroys virtual RX_RING buffer
57 * @sock: socket
58 * @rb: ring buffer
60 void destroy_virt_rx_ring(int sock, ring_buff_t * rb)
62 assert(rb);
64 memset(&(rb->layout), 0, sizeof(rb->layout));
65 setsockopt(sock, SOL_PACKET, PACKET_RX_RING, (void *)&(rb->layout), sizeof(rb->layout));
67 if (rb->buffer) {
68 munmap(rb, rb->len);
69 rb->buffer = 0;
70 rb->len = 0;
73 free(rb->frames);
76 /**
77 * create_virt_rx_ring - Creates virtual RX_RING buffer
78 * @sock: socket
79 * @rb: ring buffer
81 void create_virt_rx_ring(int sock, ring_buff_t * rb, char *ifname, unsigned int usize)
83 short nic_flags;
84 int ret, dev_speed;
86 assert(rb);
87 assert(ifname);
89 nic_flags = get_nic_flags(ifname);
91 if ((nic_flags & IFF_UP) != IFF_UP) {
92 warn("The interface %s is not up\n\n", ifname);
93 exit(EXIT_FAILURE);
96 if ((nic_flags & IFF_RUNNING) != IFF_RUNNING) {
97 warn("The interface %s is not running\n\n", ifname);
98 exit(EXIT_FAILURE);
101 dev_speed = get_device_bitrate_generic_fallback(ifname);
102 memset(&(rb->layout), 0, sizeof(rb->layout));
104 /* max: getpagesize() << 11 for i386 */
105 rb->layout.tp_block_size = getpagesize() << 2;
106 rb->layout.tp_frame_size = TPACKET_ALIGNMENT << 7;
108 /* max: 15 for i386, old default: 1 << 13, now: approximated bandwidth size */
109 if(usize == 0) {
110 rb->layout.tp_block_nr = ((dev_speed * 1024 * 1024) / rb->layout.tp_block_size);
111 } else {
112 rb->layout.tp_block_nr = usize / (rb->layout.tp_block_size / 1024);
115 rb->layout.tp_frame_nr = rb->layout.tp_block_size / rb->layout.tp_frame_size * rb->layout.tp_block_nr;
117 __retry_sso:
118 ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING, (void *)&(rb->layout), sizeof(rb->layout));
120 if (errno == ENOMEM && rb->layout.tp_block_nr > 1) {
121 rb->layout.tp_block_nr >>= 1;
122 rb->layout.tp_frame_nr = rb->layout.tp_block_size / rb->layout.tp_frame_size * rb->layout.tp_block_nr;
124 goto __retry_sso;
127 if (ret < 0) {
128 err("setsockopt: creation of rx_ring failed");
129 close(sock);
130 exit(EXIT_FAILURE);
133 rb->len = rb->layout.tp_block_size * rb->layout.tp_block_nr;
135 info("%.2f MB allocated for receive ring \n", 1.f * rb->len / (1024 * 1024));
136 info(" [ %d blocks, %d frames ] \n", rb->layout.tp_block_nr, rb->layout.tp_frame_nr);
137 info(" [ %d frames per block ]\n", rb->layout.tp_block_size / rb->layout.tp_frame_size);
138 info(" [ framesize: %d bytes, blocksize: %d bytes ]\n\n", rb->layout.tp_frame_size, rb->layout.tp_block_size);
142 * mmap_virt_rx_ring - Memory maps virtual RX_RING kernel buffer into userspace
143 * in order to avoid syscalls for fetching packet buffers
144 * @sock: socket
145 * @rb: ring buffer
147 void mmap_virt_rx_ring(int sock, ring_buff_t * rb)
149 assert(rb);
151 rb->buffer = mmap(0, rb->len, PROT_READ | PROT_WRITE, MAP_SHARED, sock, 0);
152 if (rb->buffer == MAP_FAILED) {
153 err("mmap: cannot mmap the rx_ring");
155 destroy_virt_rx_ring(sock, rb);
156 close(sock);
157 exit(EXIT_FAILURE);
162 * bind_dev_to_rx_ring - Binds virtual RX_RING to network device
163 * @sock: socket
164 * @ifindex: device number
165 * @rb: ring buffer
167 void bind_dev_to_rx_ring(int sock, int ifindex, ring_buff_t * rb)
169 int ret;
171 assert(rb);
173 memset(&(rb->params), 0, sizeof(rb->params));
175 rb->params.sll_family = AF_PACKET;
176 rb->params.sll_protocol = htons(ETH_P_ALL);
177 rb->params.sll_ifindex = ifindex;
178 rb->params.sll_hatype = 0;
179 rb->params.sll_halen = 0;
180 rb->params.sll_pkttype = 0;
182 ret = bind(sock, (struct sockaddr *)&(rb->params), sizeof(struct sockaddr_ll));
183 if (ret < 0) {
184 err("bind: cannot bind device");
186 close(sock);
187 exit(EXIT_FAILURE);
192 * fetch_packets_and_print - Traverses RX_RING and prints content
193 * @rb: ring buffer
194 * @pfd: file descriptor for polling
196 void fetch_packets(system_data_t * sd, int sock, ring_buff_t * rb, struct pollfd *pfd)
198 int ret, foo, i = 0;
200 pthread_t progress;
202 assert(rb);
203 assert(pfd);
204 assert(sd);
206 info("--- Listening ---\n\n");
208 if (!sd->print_pkt)
209 enable_print_progress_spinner();
211 if (sd->pcap_fd != PCAP_NO_DUMP) {
212 pcap_write_header(sd->pcap_fd, LINKTYPE_EN10MB, 0, PCAP_DEFAULT_SNAPSHOT_LEN);
214 if (!sd->print_pkt) {
215 ret =
216 pthread_create(&progress, NULL, print_progress_spinner_static,
217 "Receive ring dumping ... |");
218 if (ret) {
219 err("Cannot create thread");
220 exit(EXIT_FAILURE);
225 /* This is our critical path ... */
226 while (likely(!sigint)) {
227 while (mem_notify_user_for_rx(rb->frames[i]) && likely(!sigint)) {
228 struct frame_map *fm = rb->frames[i].iov_base;
229 ring_buff_bytes_t *rbb =
230 (ring_buff_bytes_t *) ((uint8_t *) rb->frames[i].iov_base + sizeof(*fm) + sizeof(short));
232 /* Check if the user wants to have a specific
233 packet type */
234 if (sd->packet_type != PACKET_DONT_CARE) {
235 if (fm->s_ll.sll_pkttype != sd->packet_type) {
236 goto __out_notify_kernel;
240 if (sd->pcap_fd != PCAP_NO_DUMP) {
241 pcap_dump(sd->pcap_fd, &fm->tp_h, (struct ethhdr *)rbb);
242 print_progress_spinner_dynamic_trigger();
245 if (sd->print_pkt) {
246 /* This path here slows us down ... well, but
247 the user wants to see what's going on */
248 sd->print_pkt(rbb, &fm->tp_h);
251 /* Pending singals will be delivered after netstat
252 manipulation */
253 hold_softirq(2, SIGUSR1, SIGALRM);
254 /* XXX: futex */
255 pthread_mutex_lock(&gs_loc_mutex);
257 netstat.per_sec.frames++;
258 netstat.per_sec.bytes += fm->tp_h.tp_len;
260 netstat.total.frames++;
261 netstat.total.bytes += fm->tp_h.tp_len;
263 pthread_mutex_unlock(&gs_loc_mutex);
264 restore_softirq(2, SIGUSR1, SIGALRM);
266 /* Next frame */
267 i = (i + 1) % rb->layout.tp_frame_nr;
269 __out_notify_kernel:
270 /* This is very important, otherwise kernel starts
271 to drop packages */
272 mem_notify_kernel_for_rx(&(fm->tp_h));
275 while ((ret = poll(pfd, 1, sd->blocking_mode)) <= 0) {
276 if (sigint) {
277 printf("Got SIGINT here!\n");
279 if (!sd->print_pkt)
280 disable_print_progress_spinner();
282 return;
286 if (ret > 0 && (pfd->revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))) {
287 if (pfd->revents & (POLLHUP | POLLRDHUP)) {
288 err("Hangup on socket occured");
290 if (!sd->print_pkt)
291 disable_print_progress_spinner();
293 return;
294 } else if (pfd->revents & POLLERR) {
295 /* recv is more specififc on the error */
296 errno = 0;
297 if (recv(sock, &foo, sizeof(foo), MSG_PEEK) != -1)
298 goto __out_grab_frame; /* Hmm... no error */
299 if (errno == ENETDOWN) {
300 err("Interface went down");
301 } else {
302 err("Receive error");
305 if (!sd->print_pkt)
306 disable_print_progress_spinner();
308 return;
309 } else if (pfd->revents & POLLNVAL) {
310 err("Invalid polling request on socket");
312 if (!sd->print_pkt)
313 disable_print_progress_spinner();
315 return;
319 __out_grab_frame:
320 /* Look-ahead if current frame is status kernel, otherwise we have
321 have incoming frames and poll spins / hangs all the time :( */
322 for (; ((struct tpacket_hdr *)rb->frames[i].iov_base)->tp_status
323 != TP_STATUS_USER; i = (i + 1) % rb->layout.tp_frame_nr)
324 /* NOP */ ;
325 /* Why this should be okay:
326 1) Current frame[i] is TP_STATUS_USER:
327 This is our original case that occurs without
328 the for loop.
329 2) Current frame[i] is not TP_STATUS_USER:
330 poll returns correctly with return value 1 (number of
331 file descriptors), so an event has occured which has
332 to be POLLIN since all error conditions have been
333 caught previously. Furthermore, during ring traversal
334 a frame that has been set to TP_STATUS_USER will be
335 given back to kernel on finish with TP_STATUS_KERNEL.
336 So, if we look ahead all skipped frames are not ready
337 for user access. Since the kernel decides to put
338 frames, which are 'behind' our pointer, into
339 TP_STATUS_USER we do one loop and return at the
340 correct position after passing the for loop again. If
341 we grab frame which are 'in front of' our pointer
342 we'll fetch them within the first for loop.
346 if (!sd->print_pkt)
347 disable_print_progress_spinner();