source: lib/format_linux_ring.c @ 771ab22

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 771ab22 was 1871afc, checked in by Richard Sanger <rsangerarj@…>, 6 years ago

Add missing files

  • Property mode set to 100644
File size: 26.1 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *          Richard Sanger
11 *
12 * All rights reserved.
13 *
14 * This code has been developed by the University of Waikato WAND
15 * research group. For further information please see http://www.wand.net.nz/
16 *
17 * libtrace is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * libtrace is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with libtrace; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30 *
31 * $Id$
32 *
33 */
34
35/* This format module deals with using the Linux Ring capture format (also
36 * known as PACKET_MMAP).
37 *
38 * Linux Ring is a LIVE capture format.
39 *
40 * This format also supports writing which will write packets out to the
41 * network as a form of packet replay. This should not be confused with the
42 * RT protocol which is intended to transfer captured packet records between
43 * RT-speaking programs.
44 */
45
46#include "config.h"
47#include "libtrace.h"
48#include "libtrace_int.h"
49#include "format_helper.h"
50#include "libtrace_arphrd.h"
51#include <stdlib.h>
52#include <errno.h>
53#include <unistd.h>
54#include <string.h>
55#include <assert.h>
56
57#ifdef HAVE_INTTYPES_H
58#  include <inttypes.h>
59#else
60# error "Can't find inttypes.h"
61#endif
62
63#include "format_linux.h"
64
65#ifdef HAVE_NETPACKET_PACKET_H
66/* Get current frame in the ring buffer*/
67#define GET_CURRENT_BUFFER(libtrace) \
68        ((void *)FORMAT_DATA_FIRST->rx_ring +                           \
69         (FORMAT_DATA_FIRST->rxring_offset *                            \
70          FORMAT_DATA->req.tp_frame_size))
71#endif
72
73/* Get the start of the captured data. I'm not sure if tp_mac (link layer) is
74 * always guaranteed. If it's not there then just use tp_net.
75 */
76#define TP_TRACE_START(mac, net, hdrend) \
77        ((mac) > (hdrend) && (mac) < (net) ? (mac) : (net))
78
79/*
80 * Try figure out the best sizes for the ring buffer. Ensure that:
81 * - max(Block_size) == page_size << max_order
82 * - Frame_size == page_size << x (so that block_size%frame_size == 0)
83 *   This means that there will be no wasted space between blocks
84 * - Frame_size < block_size
85 * - Frame_size is as close as possible to LIBTRACE_PACKET_BUFSIZE, but not
86 *   bigger
87 * - Frame_nr = Block_nr * (frames per block)
88 * - CONF_RING_FRAMES is used a minimum number of frames to hold
89 * - Calculates based on max_order and buf_min
90 */
91static void calculate_buffers(struct tpacket_req * req, int fd, char * uri,
92                uint32_t max_order)
93{
94        struct ifreq ifr;
95        unsigned max_frame = LIBTRACE_PACKET_BUFSIZE;
96        pagesize = getpagesize();
97
98        strcpy(ifr.ifr_name, uri);
99        /* Don't bother trying to set frame size above mtu linux will drop
100         * these anyway.
101         *
102         * Remember, that our frame also has to include a TPACKET header!
103         */
104        if (ioctl(fd, SIOCGIFMTU, (caddr_t)&ifr) >= 0)
105                max_frame = ifr.ifr_mtu + TPACKET_ALIGN(TPACKET2_HDRLEN);
106        if (max_frame > LIBTRACE_PACKET_BUFSIZE)
107                max_frame = LIBTRACE_PACKET_BUFSIZE;
108
109        /* Calculate frame size */
110        req->tp_frame_size = pagesize;
111        while (req->tp_frame_size < max_frame &&
112              req->tp_frame_size < LIBTRACE_PACKET_BUFSIZE) {
113                req->tp_frame_size <<= 1;
114        }
115        if (req->tp_frame_size > LIBTRACE_PACKET_BUFSIZE)
116                req->tp_frame_size >>= 1;
117
118        /* Calculate block size */
119        req->tp_block_size = pagesize << max_order;
120        do {
121                req->tp_block_size >>= 1;
122        } while ((CONF_RING_FRAMES * req->tp_frame_size) <= req->tp_block_size);
123        req->tp_block_size <<= 1;
124
125        /* Calculate number of blocks */
126        req->tp_block_nr = (CONF_RING_FRAMES * req->tp_frame_size)
127                / req->tp_block_size;
128        if((CONF_RING_FRAMES * req->tp_frame_size) % req->tp_block_size != 0)
129                req->tp_block_nr++;
130
131        /* Calculate packets such that we use all the space we have to
132         * allocated */
133        req->tp_frame_nr = req->tp_block_nr *
134                (req->tp_block_size / req->tp_frame_size);
135
136        /*
137        printf("MaxO 0x%x BS 0x%x BN 0x%x FS 0x%x FN 0x%x\n",
138                max_order,
139                req->tp_block_size,
140                req->tp_block_nr,
141                req->tp_frame_size,
142                req->tp_frame_nr);
143        */
144
145        /* In case we have some silly values*/
146        assert(req->tp_block_size);
147        assert(req->tp_block_nr);
148        assert(req->tp_frame_size);
149        assert(req->tp_frame_nr);
150        assert(req->tp_block_size % req->tp_frame_size == 0);
151}
152
153static inline int socket_to_packetmmap( char * uridata, int ring_type,
154                                        int fd,
155                                        struct tpacket_req * req,
156                                        char ** ring_location,
157                                        uint32_t *max_order,
158                                        char *error) {
159        int val;
160
161        /* Switch to TPACKET header version 2, we only try support v2 because
162         * v1 had problems with data type consistancy */
163        val = TPACKET_V2;
164        if (setsockopt(fd,
165                       SOL_PACKET,
166                       PACKET_VERSION,
167                       &val,
168                       sizeof(val)) == -1) {
169                strncpy(error, "TPACKET2 not supported", 2048);
170                return -1;
171        }
172
173        /* Try switch to a ring buffer. If it fails we assume the the kernel
174         * cannot allocate a block of that size, so decrease max_block and
175         * retry.
176         */
177        while(1) {
178                if (*max_order <= 0) {
179                        strncpy(error,
180                                "Cannot allocate enough memory for ring buffer",
181                                2048);
182                        return -1;
183                }
184                calculate_buffers(req, fd, uridata, *max_order);
185                if (setsockopt(fd,
186                               SOL_PACKET,
187                               ring_type,
188                               req,
189                               sizeof(struct tpacket_req)) == -1) {
190                        if(errno == ENOMEM) {
191                                (*max_order)--;
192                        } else {
193                                strncpy(error,
194                                        "Error setting the ring buffer size",
195                                        2048);
196                                return -1;
197                        }
198
199                } else break;
200        }
201
202        /* Map the ring buffer into userspace */
203        *ring_location = mmap(NULL,
204                              req->tp_block_size * req->tp_block_nr,
205                              PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
206        if(*ring_location == MAP_FAILED) {
207                strncpy(error, "Failed to map memory for ring buffer", 2048);
208                return -1;
209        }
210
211        return 0;
212}
213
214/* Release a frame back to the kernel or free() if it's a malloc'd buffer
215 */
216inline static void ring_release_frame(libtrace_t *libtrace,
217                                      libtrace_packet_t *packet)
218{
219        /* Free the old packet */
220        if(packet->buffer == NULL)
221                return;
222
223        if(packet->buf_control == TRACE_CTRL_PACKET){
224                free(packet->buffer);
225                packet->buffer = NULL;
226        }
227
228        if(packet->buf_control == TRACE_CTRL_EXTERNAL) {
229                struct linux_format_data_t *ftd = FORMAT_DATA;
230
231                /* Check it's within our buffer first - consider the pause
232                 * resume case it might have already been free'd lets hope we
233                 * get another buffer */
234                // TODO: For now let any one free anything
235                /*if(LIBTRACE_BETWEEN((char *) packet->buffer,
236                                (char *) ftd->rx_ring,
237                                ftd->rx_ring +
238                                ftd->req.tp_block_size *
239                                ftd->req.tp_block_nr)){*/
240                TO_TP_HDR2(packet->buffer)->tp_status = 0;
241                packet->buffer = NULL;
242                /*}*/
243        }
244}
245
246static int linuxring_init_input(libtrace_t *libtrace)
247{
248        /* Used to bootstrap the format data. We also save it later as it's very
249         * useful to us. */
250        struct libtrace_format_t *parent = get_native_format();
251
252        /* This function will allocate the format data memory as well as
253         * initialising all the native relevant fields. Anything native doesn't
254         * touch will be touched here. */
255        parent->init_input(libtrace);
256
257        FORMAT_DATA->format = TRACE_RT_DATA_LINUX_RING;
258        FORMAT_DATA->parent_format = parent;
259
260        FORMAT_DATA_FIRST->rx_ring = NULL;
261        FORMAT_DATA_FIRST->rxring_offset = 0;
262        FORMAT_DATA->max_order = MAX_ORDER;
263
264        /* If we haven't already, we need to update all the fields in our
265         * format to point to the relevant fields in the parent format */
266        if (libtrace->format->get_filtered_packets == NULL) {
267#ifdef HAVE_NETPACKET_PACKET_H
268                libtrace->format->probe_filename = parent->probe_filename;
269                libtrace->format->config_input = parent->config_input;
270                libtrace->format->fin_input = parent->fin_input;
271
272                libtrace->format->pstart_input = parent->pstart_input;
273                libtrace->format->ppause_input = parent->ppause_input;
274                libtrace->format->pfin_input = parent->fin_input;
275                libtrace->format->pconfig_input = parent->pconfig_input;
276                libtrace->format->pregister_thread = parent->pregister_thread;
277#endif
278                libtrace->format->get_filtered_packets =
279                        parent->get_filtered_packets;
280                libtrace->format->get_dropped_packets =
281                        parent->get_dropped_packets;
282                libtrace->format->get_captured_packets =
283                        parent->get_captured_packets;
284                libtrace->format->get_fd = parent->get_fd;
285        }
286
287        return 0;
288}
289
290static int linuxring_start_input(libtrace_t *libtrace)
291{
292        char error[2048];
293
294        /* We set the socket up the same and then convert it to PACKET_MMAP */
295        if(PARENT->start_input(libtrace) != 0)
296                return -1;
297
298        strncpy(error, "No known error", 2048);
299
300        /* Make it a packetmmap */
301        if(socket_to_packetmmap(libtrace->uridata, PACKET_RX_RING,
302                                FORMAT_DATA_FIRST->fd,
303                                &FORMAT_DATA->req,
304                                &FORMAT_DATA_FIRST->rx_ring,
305                                &FORMAT_DATA->max_order,
306                                error) != 0) {
307                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
308                              "Initialisation of packet MMAP failed: %s",
309                              error);
310                close(FORMAT_DATA_FIRST->fd);
311                free(libtrace->format_data);
312                libtrace->format_data = NULL;
313                return -1;
314        }
315
316        return 0;
317}
318
319static int linuxring_pause_input(libtrace_t *libtrace)
320{
321        munmap(FORMAT_DATA_FIRST->rx_ring,
322               FORMAT_DATA->req.tp_block_size *
323               FORMAT_DATA->req.tp_block_nr);
324        FORMAT_DATA_FIRST->rx_ring = NULL;
325        return PARENT->pause_input(libtrace);
326}
327
328static int linuxring_init_output(libtrace_out_t *libtrace)
329{
330        /* Used to bootstrap the format data. We also save it later as it's very
331         * useful to us. */
332        struct libtrace_format_t *parent = get_native_format();
333
334        /* This function will allocate the format data memory as well as
335         * initialising all the native relevant fields. Anything native doesn't
336         * touch will be touched here. */
337        parent->init_output(libtrace);
338
339        FORMAT_DATA_OUT->format = TRACE_FORMAT_LINUX_RING;
340        FORMAT_DATA_OUT->parent_format = parent;
341
342        /* If we haven't already, we need to update all the fields in our
343         * format to point to the relevant fields in the parent format */
344        if (libtrace->format->get_filtered_packets == NULL) {
345#ifdef HAVE_NETPACKET_PACKET_H
346                libtrace->format->probe_filename = parent->probe_filename;
347                libtrace->format->config_input = parent->config_input;
348                libtrace->format->fin_input = parent->fin_input;
349
350                libtrace->format->pstart_input = parent->pstart_input;
351                libtrace->format->ppause_input = parent->ppause_input;
352                libtrace->format->pfin_input = parent->fin_input;
353                libtrace->format->pconfig_input = parent->pconfig_input;
354                libtrace->format->pregister_thread = parent->pregister_thread;
355#endif
356                libtrace->format->get_filtered_packets =
357                        parent->get_filtered_packets;
358                libtrace->format->get_dropped_packets =
359                        parent->get_dropped_packets;
360                libtrace->format->get_captured_packets =
361                        parent->get_captured_packets;
362                libtrace->format->get_fd = parent->get_fd;
363        }
364
365        return 0;
366}
367
368static int linuxring_start_output(libtrace_out_t *libtrace)
369{
370        char error[2048];
371        /* We set the socket up the same and then convert it to PACKET_MMAP */
372        if (PARENT_OUT->start_output(libtrace) != 0)
373                return -1;
374
375        /* Make it a packetmmap */
376        if(socket_to_packetmmap(libtrace->uridata, PACKET_TX_RING,
377                                FORMAT_DATA_OUT->fd,
378                                &FORMAT_DATA_OUT->req,
379                                &FORMAT_DATA_OUT->tx_ring,
380                                &FORMAT_DATA_OUT->max_order,
381                                error) != 0) {
382                trace_set_err_out(libtrace, TRACE_ERR_INIT_FAILED,
383                                  "Initialisation of packet MMAP failed: %s",
384                                  error);
385                close(FORMAT_DATA_OUT->fd);
386                free(FORMAT_DATA_OUT);
387                libtrace->format_data = NULL;
388                return -1;
389        }
390
391        FORMAT_DATA_OUT->sock_hdr.sll_family = AF_PACKET;
392        FORMAT_DATA_OUT->sock_hdr.sll_protocol = 0;
393        FORMAT_DATA_OUT->sock_hdr.sll_ifindex =
394                if_nametoindex(libtrace->uridata);
395        FORMAT_DATA_OUT->sock_hdr.sll_hatype = 0;
396        FORMAT_DATA_OUT->sock_hdr.sll_pkttype = 0;
397        FORMAT_DATA_OUT->sock_hdr.sll_halen = 0;
398        FORMAT_DATA_OUT->queue = 0;
399
400        return 0;
401}
402
403static int linuxring_fin_output(libtrace_out_t *libtrace)
404{
405        /* Make sure any remaining frames get sent */
406        sendto(FORMAT_DATA_OUT->fd,
407               NULL,
408               0,
409               0,
410               (void *) &FORMAT_DATA_OUT->sock_hdr,
411               sizeof(FORMAT_DATA_OUT->sock_hdr));
412
413        /* Unmap our data area */
414        munmap(FORMAT_DATA_OUT->tx_ring,
415               FORMAT_DATA_OUT->req.tp_block_size *
416               FORMAT_DATA_OUT->req.tp_block_nr);
417
418        return PARENT_OUT->fin_output(libtrace);
419}
420
421static int linuxring_read_packet(libtrace_t *libtrace,
422                                 libtrace_packet_t *packet)
423{
424        /* Read a single packet from the ring at FORMAT_DATA_FIRST */
425        return -1;
426}
427
428static int linuxring_pread_packets(libtrace_t *libtrace,
429                                   libtrace_thread_t *t,
430                                   libtrace_packet_t **packets,
431                                   size_t nb_packets)
432{
433        struct linux_per_stream_t *stream_data =
434                (struct linux_per_stream_t *)t->format_data;
435        return -1;
436}
437
438#if 0
439/* This is the way we used to do it. Might be useful to copy some of this
440 * into the new code */
441inline static int linuxring_read_packet_fd(libtrace_t *libtrace, libtrace_packet_t *packet, int fd, int *rxring_offset, char *rx_ring, int message) {
442
443        struct tpacket2_hdr *header;
444        int ret;
445        unsigned int snaplen;
446       
447        ring_release_frame(libtrace, packet);
448       
449        packet->buf_control = TRACE_CTRL_EXTERNAL;
450        packet->type = TRACE_RT_DATA_LINUX_RING;
451       
452        /* Fetch the current frame */
453        header = ((void*) rx_ring) + *rxring_offset * FORMAT(libtrace->format_data)->req.tp_frame_size; // GET_CURRENT_BUFFER(libtrace);
454        assert((((unsigned long) header) & (pagesize - 1)) == 0);
455
456        /* TP_STATUS_USER means that we can use the frame.
457         * When a slot does not have this flag set, the frame is not
458         * ready for consumption.
459         */
460        while (!(header->tp_status & TP_STATUS_USER)) {
461                if (message) {
462                        struct pollfd pollset[2];
463                        pollset[0].fd = fd;
464                        pollset[0].events = POLLIN;
465                        pollset[0].revents = 0;
466                        pollset[1].fd = libtrace_message_queue_get_fd(&get_thread_table(libtrace)->messages);
467                        pollset[1].events = POLLIN;
468                        pollset[1].revents = 0;
469                        /* Wait for more data or a message*/
470                        ret = poll(pollset, 2, -1);
471                        if (ret < 0) {
472                                if (errno != EINTR)
473                                        trace_set_err(libtrace,errno,"poll()");
474                                return -1;
475                        }
476                        /* A message is ready */
477                        if (pollset[1].revents)
478                                return -2;
479                } else {
480                        struct pollfd pollset;
481                        pollset.fd = fd;
482                        pollset.events = POLLIN;
483                        pollset.revents = 0;
484
485                        /* Wait for more data or a message*/
486                        ret = poll(&pollset, 1, 500);
487                        if (ret < 0) {
488                                if (errno != EINTR)
489                                        trace_set_err(libtrace,errno,"poll()");
490                                return -1;
491                        } else if (ret == 0) {
492                                /* Poll timed out - check if we should exit */
493                                if (libtrace_halt)
494                                        return 0;
495                                continue;
496                        }
497                }
498        }
499
500        packet->buffer = header;
501
502        /* If a snaplen was configured, automatically truncate the packet to
503         * the desired length.
504         */
505        snaplen=LIBTRACE_MIN(
506                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*header),
507                        (int)FORMAT(libtrace->format_data)->snaplen);
508       
509        TO_TP_HDR2(packet->buffer)->tp_snaplen = LIBTRACE_MIN((unsigned int)snaplen, TO_TP_HDR2(packet->buffer)->tp_len);
510
511        /* Move to next buffer */
512        (*rxring_offset)++;
513        *rxring_offset %= FORMAT(libtrace->format_data)->req.tp_frame_nr;
514
515        /* We just need to get prepare_packet to set all our packet pointers
516         * appropriately */
517        if (linuxring_prepare_packet(libtrace, packet, packet->buffer,
518                                packet->type, 0))
519                return -1;
520        return  linuxring_get_framing_length(packet) +
521                                linuxring_get_capture_length(packet);
522
523}
524
525static int linuxring_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
526        int fd = FORMAT(libtrace->format_data)->fd;
527        int *rxring_offset = &FORMAT(libtrace->format_data)->rxring_offset;
528        char *rx_ring = FORMAT(libtrace->format_data)->rx_ring;
529        return linuxring_read_packet_fd(libtrace, packet, fd, rxring_offset, rx_ring, 0);
530}
531
532static int linuxring_pread_packets(libtrace_t *libtrace,
533                                   libtrace_thread_t *t,
534                                   libtrace_packet_t **packets,
535                                   UNUSED size_t nb_packets) {
536        //fprintf(stderr, "Thread number is #%d\n", t->perpkt_num);
537        int fd = PERPKT_FORMAT(t)->fd;
538        int *rxring_offset = &PERPKT_FORMAT(t)->rxring_offset;
539        char *rx_ring = PERPKT_FORMAT(t)->rx_ring;
540        packets[0]->error = linuxring_read_packet_fd(libtrace, packets[0], fd,
541                                                     rxring_offset, rx_ring, 1);
542        if (packets[0]->error >= 1)
543                return 1;
544        else
545                return packets[0]->error;
546}
547#endif /* 0 */
548
549/* Non-blocking read */
550static libtrace_eventobj_t linuxring_event(libtrace_t *libtrace,
551                                           libtrace_packet_t *packet)
552{
553        struct tpacket2_hdr *header;
554        libtrace_eventobj_t event = {0,0,0.0,0};
555
556        /* We must free the old packet, otherwise select() will instantly
557         * return */
558        ring_release_frame(libtrace, packet);
559
560        /* Fetch the current frame */
561        header = GET_CURRENT_BUFFER(libtrace);
562        if (header->tp_status & TP_STATUS_USER) {
563                /* We have a frame waiting */
564                event.size = trace_read_packet(libtrace, packet);
565                event.type = TRACE_EVENT_PACKET;
566        } else {
567                /* Ok we don't have a packet waiting */
568                event.type = TRACE_EVENT_IOWAIT;
569                event.fd = FORMAT_DATA_FIRST->fd;
570        }
571
572        return event;
573}
574
575static int linuxring_prepare_packet(libtrace_t *libtrace UNUSED,
576                                    libtrace_packet_t *packet, void *buffer,
577                                    libtrace_rt_types_t rt_type, uint32_t flags)
578{
579        if (packet->buffer != buffer &&
580            packet->buf_control == TRACE_CTRL_PACKET) {
581                free(packet->buffer);
582        }
583
584        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER)
585                packet->buf_control = TRACE_CTRL_PACKET;
586        else
587                packet->buf_control = TRACE_CTRL_EXTERNAL;
588
589
590        packet->buffer = buffer;
591        packet->header = buffer;
592        packet->payload = (char *)buffer +
593                TP_TRACE_START(TO_TP_HDR2(packet->header)->tp_mac,
594                               TO_TP_HDR2(packet->header)->tp_net,
595                               TPACKET2_HDRLEN);
596        packet->type = rt_type;
597
598        return 0;
599}
600
601/**
602 * Free any resources being kept for this packet, Note: libtrace
603 * will ensure all fields are zeroed correctly.
604 */
605static void linuxring_fin_packet(libtrace_packet_t *packet)
606{
607        libtrace_t *libtrace = packet->trace;
608
609        if (packet->buffer == NULL)
610                return;
611        assert(packet->trace);
612
613        /* If we own the packet (i.e. it's not a copy), we need to free it */
614        if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
615                /* Started should always match the existence of the rx_ring */
616                assert(!!FORMAT_DATA_FIRST->rx_ring ==
617                       !!packet->trace->started);
618                /* If we don't have a ring its already been destroyed */
619                if (FORMAT_DATA_FIRST->rx_ring)
620                        ring_release_frame(packet->trace, packet);
621                else
622                        packet->buffer = NULL;
623        }
624}
625
626static int linuxring_write_packet(libtrace_out_t *libtrace,
627                                  libtrace_packet_t *packet)
628{
629        struct tpacket2_hdr *header;
630        struct pollfd pollset;
631        struct socket_addr;
632        int ret;
633        unsigned max_size;
634        void * off;
635
636        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
637                return 0;
638
639        max_size = FORMAT_DATA_OUT->req.tp_frame_size -
640                TPACKET2_HDRLEN + sizeof(struct sockaddr_ll);
641
642        header = (void *)FORMAT_DATA_OUT->tx_ring +
643                (FORMAT_DATA_OUT->txring_offset *
644                 FORMAT_DATA_OUT->req.tp_frame_size);
645
646        while(header->tp_status != TP_STATUS_AVAILABLE) {
647                /* if none available: wait on more data */
648                pollset.fd = FORMAT_DATA_OUT->fd;
649                pollset.events = POLLOUT;
650                pollset.revents = 0;
651                ret = poll(&pollset, 1, 1000);
652                if (ret < 0 && errno != EINTR) {
653                        perror("poll");
654                        return -1;
655                }
656                if(ret == 0)
657                        /* Timeout something has gone wrong - maybe the queue is
658                         * to large so try issue another send command
659                         */
660                        ret = sendto(FORMAT_DATA_OUT->fd,
661                                     NULL,
662                                     0,
663                                     0,
664                                     (void *)&FORMAT_DATA_OUT->sock_hdr,
665                                     sizeof(FORMAT_DATA_OUT->sock_hdr));
666                        if (ret < 0) {
667                                trace_set_err_out(libtrace, errno,
668                                                  "sendto after timeout "
669                                                  "failed");
670                                return -1;
671                        }
672        }
673
674        header->tp_len = trace_get_capture_length(packet);
675
676        /* We cannot write the whole packet so just write part of it */
677        if (header->tp_len > max_size)
678                header->tp_len = max_size;
679
680        /* Fill packet - no sockaddr_ll in header when writing to the TX_RING */
681        off = ((void *)header) + (TPACKET2_HDRLEN - sizeof(struct sockaddr_ll));
682        memcpy(off, (char *)packet->payload, header->tp_len);
683
684        /* 'Send it' and increase ring pointer to the next frame */
685        header->tp_status = TP_STATUS_SEND_REQUEST;
686        FORMAT_DATA_OUT->txring_offset = (FORMAT_DATA_OUT->txring_offset + 1) %
687                FORMAT_DATA_OUT->req.tp_frame_nr;
688
689        /* Notify kernel there are frames to send */
690        FORMAT_DATA_OUT->queue ++;
691        FORMAT_DATA_OUT->queue %= TX_MAX_QUEUE;
692        if(FORMAT_DATA_OUT->queue == 0){
693                ret = sendto(FORMAT_DATA_OUT->fd,
694                                NULL,
695                                0,
696                                MSG_DONTWAIT,
697                                (void *)&FORMAT_DATA_OUT->sock_hdr,
698                                sizeof(FORMAT_DATA_OUT->sock_hdr));
699                if (ret < 0) {
700                        trace_set_err_out(libtrace, errno, "sendto failed");
701                        return -1;
702                }
703        }
704        return header->tp_len;
705
706}
707
708static libtrace_linktype_t
709linuxring_get_link_type(const struct libtrace_packet_t *packet)
710{
711        uint16_t linktype = GET_SOCKADDR_HDR(packet->buffer)->sll_hatype;
712        return get_libtrace_link_type(linktype);
713}
714
715static libtrace_direction_t
716linuxring_get_direction(const struct libtrace_packet_t *packet) {
717        return get_libtrace_direction(GET_SOCKADDR_HDR(packet->buffer)->
718                                      sll_pkttype);
719}
720
721static libtrace_direction_t
722linuxring_set_direction(libtrace_packet_t *packet,
723                        libtrace_direction_t direction) {
724        return set_direction(GET_SOCKADDR_HDR(packet->buffer), direction);
725}
726
727static struct timeval linuxring_get_timeval(const libtrace_packet_t *packet)
728{
729        struct timeval tv;
730        tv.tv_sec = TO_TP_HDR2(packet->buffer)->tp_sec;
731        tv.tv_usec = TO_TP_HDR2(packet->buffer)->tp_nsec / 1000;
732        return tv;
733}
734
735static struct timespec linuxring_get_timespec(const libtrace_packet_t *packet)
736{
737        struct timespec ts;
738        ts.tv_sec = TO_TP_HDR2(packet->buffer)->tp_sec;
739        ts.tv_nsec = TO_TP_HDR2(packet->buffer)->tp_nsec;
740        return ts;
741}
742
743static int linuxring_get_capture_length(const libtrace_packet_t *packet)
744{
745        return TO_TP_HDR2(packet->buffer)->tp_snaplen;
746}
747
748static int linuxring_get_wire_length(const libtrace_packet_t *packet)
749{
750        int wirelen = TO_TP_HDR2(packet->buffer)->tp_len;
751
752        /* Include the missing FCS */
753        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
754                wirelen += 4;
755
756        return wirelen;
757}
758
759static int linuxring_get_framing_length(const libtrace_packet_t *packet)
760{
761        /*
762         * Need to make frame_length + capture_length = complete capture length
763         * so include alligment whitespace. So reverse calculate from packet.
764         */
765        return (char *)packet->payload - (char *)packet->buffer;
766}
767
768static size_t linuxring_set_capture_length(libtrace_packet_t *packet,
769                                           size_t size)
770{
771        assert(packet);
772        if (size > trace_get_capture_length(packet)) {
773                /* We should avoid making a packet larger */
774                return trace_get_capture_length(packet);
775        }
776
777        /* Reset the cached capture length */
778        packet->capture_length = -1;
779
780        TO_TP_HDR2(packet->buffer)->tp_snaplen = size;
781
782        return trace_get_capture_length(packet);
783}
784
785#ifdef HAVE_NETPACKET_PACKET_H
786
787static void linuxring_help(void)
788{
789        printf("linuxring format module: $Revision: 1793 $\n");
790        printf("Supported input URIs:\n");
791        printf("\tring:eth0\n");
792        printf("\n");
793        printf("Supported output URIs:\n");
794        printf("\tring:eth0\n");
795        printf("\n");
796        return;
797}
798
799static struct libtrace_format_t linuxring = {
800        "ring",
801        "$Id$",
802        TRACE_FORMAT_LINUX_RING,
803        NULL,                           /* probe filename */
804        NULL,                           /* probe magic */
805        linuxring_init_input,           /* init_input */
806        NULL,                           /* config_input */
807        linuxring_start_input,          /* start_input */
808        linuxring_pause_input,          /* pause_input */
809        linuxring_init_output,          /* init_output */
810        NULL,                           /* config_output */
811        linuxring_start_output,         /* start_ouput */
812        NULL,                           /* fin_input */
813        linuxring_fin_output,           /* fin_output */
814        linuxring_read_packet,          /* read_packet */
815        linuxring_prepare_packet,       /* prepare_packet */
816        linuxring_fin_packet,           /* fin_packet */
817        linuxring_write_packet,         /* write_packet */
818        linuxring_get_link_type,        /* get_link_type */
819        linuxring_get_direction,        /* get_direction */
820        linuxring_set_direction,        /* set_direction */
821        NULL,                           /* get_erf_timestamp */
822        linuxring_get_timeval,          /* get_timeval */
823        linuxring_get_timespec,         /* get_timespec */
824        NULL,                           /* get_seconds */
825        NULL,                           /* seek_erf */
826        NULL,                           /* seek_timeval */
827        NULL,                           /* seek_seconds */
828        linuxring_get_capture_length,   /* get_capture_length */
829        linuxring_get_wire_length,      /* get_wire_length */
830        linuxring_get_framing_length,   /* get_framing_length */
831        linuxring_set_capture_length,   /* set_capture_length */
832        NULL,                           /* get_received_packets */
833        NULL,                           /* get_filtered_packets */
834        NULL,                           /* get_dropped_packets */
835        NULL,                           /* get_captured_packets */
836        NULL,                           /* get_fd */
837        linuxring_event,                /* trace_event */
838        linuxring_help,                 /* help */
839        NULL,                           /* next pointer */
840        {true, -1},                     /* Live, no thread limit */
841        NULL,                           /* pstart_input */
842        linuxring_pread_packets,        /* pread_packets */
843        NULL,                           /* ppause */
844        NULL,                           /* p_fin */
845        NULL,
846        NULL,
847        NULL
848};
849#else
850
851static void linuxring_help(void)
852{
853        printf("linuxring format module: $Revision: 1793 $\n");
854        printf("Not supported on this host\n");
855}
856
857static struct libtrace_format_t linuxring = {
858        "ring",
859        "$Id$",
860        TRACE_FORMAT_LINUX_RING,
861        NULL,                           /* probe filename */
862        NULL,                           /* probe magic */
863        NULL,                           /* init_input */
864        NULL,                           /* config_input */
865        NULL,                           /* start_input */
866        NULL,                           /* pause_input */
867        NULL,                           /* init_output */
868        NULL,                           /* config_output */
869        NULL,                           /* start_ouput */
870        NULL,                           /* fin_input */
871        NULL,                           /* fin_output */
872        NULL,                           /* read_packet */
873        linuxring_prepare_packet,       /* prepare_packet */
874        NULL,                           /* fin_packet */
875        NULL,                           /* write_packet */
876        linuxring_get_link_type,        /* get_link_type */
877        linuxring_get_direction,        /* get_direction */
878        linuxring_set_direction,        /* set_direction */
879        NULL,                           /* get_erf_timestamp */
880        linuxring_get_timeval,          /* get_timeval */
881        linuxring_get_timespec,         /* get_timespec */
882        NULL,                           /* get_seconds */
883        NULL,                           /* seek_erf */
884        NULL,                           /* seek_timeval */
885        NULL,                           /* seek_seconds */
886        linuxring_get_capture_length,   /* get_capture_length */
887        linuxring_get_wire_length,      /* get_wire_length */
888        linuxring_get_framing_length,   /* get_framing_length */
889        linuxring_set_capture_length,   /* set_capture_length */
890        NULL,                           /* get_received_packets */
891        NULL,                           /* get_filtered_packets */
892        NULL,                           /* get_dropped_packets */
893        NULL,                           /* get_captured_packets */
894        NULL,                           /* get_fd */
895        NULL,                           /* trace_event */
896        linuxring_help,                 /* help */
897        NULL,                           /* next pointer */
898        NON_PARALLEL(true)
899};
900#endif
901
902/* TODO: Figure out how to give this format preference over the linux native
903 * formate if the user only specifies an interface */
904void linuxring_constructor(void)
905{
906        register_format(&linuxring);
907}
Note: See TracBrowser for help on using the repository browser.