Indention of code
[netsniff-ng.git] / src / tx_ring.c
blob0d194e878937f07fca640185761cfc62f4e9ca6f
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 #include <stdio.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <pthread.h>
28 #include <sched.h>
29 #include <signal.h>
31 #include <net/if.h>
32 #include <arpa/inet.h>
34 #include <sys/ioctl.h>
35 #include <sys/mman.h>
37 #include <linux/if_ether.h>
38 #include <linux/if_packet.h>
39 #include <linux/filter.h>
40 #include <linux/version.h>
42 #include "bpf.h"
43 #include "macros.h"
44 #include "types.h"
45 #include "replay.h"
46 #include "tx_ring.h"
47 #include "netdev.h"
48 #include "nsignal.h"
49 #include "cursor.h"
50 #include "xmalloc.h"
52 #ifdef __HAVE_TX_RING__
53 static void set_packet_loss_discard(int sock)
55 int ret;
56 int foo = 1; /* we discard wrong packets */
58 ret =
59 setsockopt(sock, SOL_PACKET, PACKET_LOSS, (void *)&foo,
60 sizeof(foo));
61 if (ret < 0) {
62 err("setsockopt: cannot set packet loss");
63 close(sock);
64 exit(EXIT_FAILURE);
68 /**
69 * destroy_virt_tx_ring - Destroys virtual TX_RING buffer
70 * @sock: socket
71 * @rb: ring buffer
73 void destroy_virt_tx_ring(int sock, struct ring_buff *rb)
75 assert(rb);
77 memset(&(rb->layout), 0, sizeof(rb->layout));
78 setsockopt(sock, SOL_PACKET, PACKET_TX_RING, (void *)&(rb->layout),
79 sizeof(rb->layout));
81 if (rb->buffer) {
82 munmap(rb->buffer, rb->len);
83 rb->buffer = 0;
84 rb->len = 0;
87 xfree(rb->frames);
90 /**
91 * create_virt_tx_ring - Creates virtual TX_RING buffer
92 * @sock: socket
93 * @rb: ring buffer
95 void create_virt_tx_ring(int sock, struct ring_buff *rb, char *ifname,
96 unsigned int usize)
98 short nic_flags;
99 int ret, dev_speed;
101 assert(rb);
102 assert(ifname);
104 nic_flags = get_nic_flags(ifname);
106 if ((nic_flags & IFF_UP) != IFF_UP) {
107 warn("The interface %s is not up\n\n", ifname);
108 exit(EXIT_FAILURE);
111 if ((nic_flags & IFF_RUNNING) != IFF_RUNNING) {
112 warn("The interface %s is not running\n\n", ifname);
113 exit(EXIT_FAILURE);
116 dev_speed = get_device_bitrate_generic_fallback(ifname);
117 memset(&(rb->layout), 0, sizeof(rb->layout));
119 set_packet_loss_discard(sock);
121 /* max: getpagesize() << 11 for i386 */
122 rb->layout.tp_block_size = getpagesize() << 2;
123 rb->layout.tp_frame_size = TPACKET_ALIGNMENT << 7;
125 /* max: 15 for i386, old default: 1 << 13, now: approximated bandwidth size */
126 if (usize == 0) {
127 rb->layout.tp_block_nr =
128 ((dev_speed * 1024 * 1024) / rb->layout.tp_block_size);
129 } else {
130 rb->layout.tp_block_nr =
131 usize / (rb->layout.tp_block_size / 1024);
134 rb->layout.tp_frame_nr =
135 rb->layout.tp_block_size / rb->layout.tp_frame_size *
136 rb->layout.tp_block_nr;
138 __retry_sso:
139 ret =
140 setsockopt(sock, SOL_PACKET, PACKET_TX_RING, (void *)&(rb->layout),
141 sizeof(rb->layout));
143 if (errno == ENOMEM && rb->layout.tp_block_nr > 1) {
144 rb->layout.tp_block_nr >>= 1;
145 rb->layout.tp_frame_nr =
146 rb->layout.tp_block_size / rb->layout.tp_frame_size *
147 rb->layout.tp_block_nr;
149 goto __retry_sso;
152 if (ret < 0) {
153 err("setsockopt: creation of tx ring failed");
154 close(sock);
155 exit(EXIT_FAILURE);
158 rb->len = rb->layout.tp_block_size * rb->layout.tp_block_nr;
160 info("%.2f MB allocated for transmit ring \n",
161 1.f * rb->len / (1024 * 1024));
162 info(" [ %d blocks, %d frames ] \n", rb->layout.tp_block_nr,
163 rb->layout.tp_frame_nr);
164 info(" [ %d frames per block ]\n",
165 rb->layout.tp_block_size / rb->layout.tp_frame_size);
166 info(" [ framesize: %d bytes, blocksize: %d bytes ]\n\n",
167 rb->layout.tp_frame_size, rb->layout.tp_block_size);
171 * mmap_virt_tx_ring - Memory maps virtual TX_RING kernel buffer into userspace
172 * in order to avoid syscalls for transmitting packet buffers
173 * @sock: socket
174 * @rb: ring buffer
176 void mmap_virt_tx_ring(int sock, struct ring_buff *rb)
178 assert(rb);
180 rb->buffer =
181 mmap(0, rb->len, PROT_READ | PROT_WRITE, MAP_SHARED, sock, 0);
182 if (rb->buffer == MAP_FAILED) {
183 err("mmap: cannot mmap the tx ring");
185 destroy_virt_tx_ring(sock, rb);
186 close(sock);
188 exit(EXIT_FAILURE);
193 * bind_dev_to_tx_ring - Binds virtual TX_RING to network device
194 * @sock: socket
195 * @ifindex: device number
196 * @rb: ring buffer
198 void bind_dev_to_tx_ring(int sock, int ifindex, struct ring_buff *rb)
200 int ret;
202 assert(rb);
204 memset(&(rb->params), 0, sizeof(rb->params));
206 rb->params.sll_family = AF_PACKET;
207 rb->params.sll_protocol = htons(ETH_P_ALL);
208 rb->params.sll_ifindex = ifindex;
209 rb->params.sll_hatype = 0;
210 rb->params.sll_halen = 0;
211 rb->params.sll_pkttype = 0;
213 ret =
214 bind(sock, (struct sockaddr *)&(rb->params),
215 sizeof(struct sockaddr_ll));
216 if (ret < 0) {
217 err("bind: cannot bind device");
218 close(sock);
219 exit(EXIT_FAILURE);
223 void transmit_packets(struct system_data *sd, int sock, struct ring_buff *rb)
225 struct frame_map *fm;
226 struct tpacket_hdr *header;
227 uint8_t *buff;
228 size_t pkt_len = 0;
229 int ret;
230 uint32_t i;
231 struct pollfd pfd;
233 assert(rb);
234 assert(sd);
236 pfd.fd = sock;
237 pfd.revents = 0;
238 pfd.events = POLLOUT;
240 info("Starting transmitting\n");
242 while (likely(!sigint)) {
243 for (i = 0; i < rb->layout.tp_block_nr; i++) {
244 fm = rb->frames[i].iov_base;
245 header = (struct tpacket_hdr *)&fm->tp_h;
246 buff =
247 (uint8_t *) ((uintptr_t) rb->frames[i].iov_base +
248 TPACKET_HDRLEN -
249 sizeof(struct sockaddr_ll));
251 switch ((volatile uint32_t)header->tp_status) {
252 case TP_STATUS_AVAILABLE:
253 while ((pkt_len =
254 pcap_fetch_next_packet(sd->pcap_fd,
255 header,
256 (struct ethhdr *)
257 buff)) != 0) {
258 /* If the fetch packet does not match the BPF, take the next one */
259 if (bpf_filter
260 (&sd->bpf, buff, header->tp_len)) {
261 break;
265 /* Prints all packets which match the BFP as unknown */
266 if (pkt_len != 0 && sd->print_pkt)
267 sd->print_pkt(buff, header, 5);
269 /* No packets to replay or error, time to exit */
270 if (pkt_len == 0)
271 goto pkt_flush;
273 /* Mark packet as ready to send */
274 header->tp_status = TP_STATUS_SEND_REQUEST;
275 break;
277 case TP_STATUS_WRONG_FORMAT:
278 warn("An error during transfer!\n");
279 exit(EXIT_FAILURE);
280 break;
282 default:
283 /* NOP */
284 break;
288 pkt_flush:
289 ret = send(sock, NULL, 0, 0);
291 if (ret < 0) {
292 err("Cannot flush tx_ring with send");
295 /* Now we wait that the kernel place all packet on the medium */
296 ret = poll(&pfd, 1, sd->blocking_mode);
298 if (ret < 0)
299 err("An error occured while polling on %s\n", sd->dev);
301 if (pkt_len == 0)
302 break;
305 #else
308 * XXX: do the same stuff but only with sendmsg or similar
311 void bind_dev_to_tx_ring(int sock, int ifindex, struct ring_buff *rb)
313 /* NOP */
316 void mmap_virt_tx_ring(int sock, struct ring_buff *rb)
318 /* NOP */
321 void create_virt_tx_ring(int sock, struct ring_buff *rb, char *ifname,
322 unsigned int usize)
324 /* NOP */
327 void destroy_virt_tx_ring(int sock, struct ring_buff *rb)
329 /* NOP */
332 int flush_virt_tx_ring(int sock, struct ring_buff *rb)
334 return 0;
337 void transmit_packets(struct system_data *sd, int sock, struct ring_buff *rb)
339 assert(rb);
340 assert(sd);
341 info("--- Transmitting ---\n\n");
343 /* Dummy function */
345 warn("The --replay functionality needs a kernel >= 2.6.31 \n\n");
347 #endif /* __HAVE_TX_RING__ */