source: lib/format_linux_ring.c @ 5ab626a

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

Deprecate trace_get_filtered/accepted/recevied/dropped() in favour of a single function

Adds the single trace_get_statistics function. This allows the structure to be filled
at a point in time, rather than making multiple calls to the library during which state
might have changed.

This has been designed such that the structure can be added to in the future without
breaking old code.

The old internal get_captured_packets was removed from the formats as it was never used.
Eventually we should completely remove get_filtered and received from the formats and replace
them with get_statistics.

In additon some extra fields have added, such as error and captured and the pre-existing
fields are better defined.

The linux formats have been updated to use this new API, which combined with reading
/proc/net/dev returns a full set of statistics.

  • Property mode set to 100644
File size: 23.7 KB
RevLine 
[1871afc]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
[6cf3ca0]63#include "format_linux_common.h"
[1871afc]64
65#ifdef HAVE_NETPACKET_PACKET_H
66/* Get current frame in the ring buffer*/
[6cf3ca0]67#define GET_CURRENT_BUFFER(libtrace, stream) \
68        ((void *)stream->rx_ring +                              \
69         (stream->rxring_offset *                               \
[1871afc]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))
[6cf3ca0]78/* Cached page size, the page size shouldn't be changing */
79static int pagesize = 0;
[1871afc]80
81/*
82 * Try figure out the best sizes for the ring buffer. Ensure that:
83 * - max(Block_size) == page_size << max_order
84 * - Frame_size == page_size << x (so that block_size%frame_size == 0)
85 *   This means that there will be no wasted space between blocks
86 * - Frame_size < block_size
87 * - Frame_size is as close as possible to LIBTRACE_PACKET_BUFSIZE, but not
88 *   bigger
89 * - Frame_nr = Block_nr * (frames per block)
90 * - CONF_RING_FRAMES is used a minimum number of frames to hold
91 * - Calculates based on max_order and buf_min
92 */
93static void calculate_buffers(struct tpacket_req * req, int fd, char * uri,
94                uint32_t max_order)
95{
96        struct ifreq ifr;
97        unsigned max_frame = LIBTRACE_PACKET_BUFSIZE;
98        pagesize = getpagesize();
99
100        strcpy(ifr.ifr_name, uri);
101        /* Don't bother trying to set frame size above mtu linux will drop
102         * these anyway.
103         *
104         * Remember, that our frame also has to include a TPACKET header!
105         */
106        if (ioctl(fd, SIOCGIFMTU, (caddr_t)&ifr) >= 0)
107                max_frame = ifr.ifr_mtu + TPACKET_ALIGN(TPACKET2_HDRLEN);
108        if (max_frame > LIBTRACE_PACKET_BUFSIZE)
109                max_frame = LIBTRACE_PACKET_BUFSIZE;
110
111        /* Calculate frame size */
112        req->tp_frame_size = pagesize;
113        while (req->tp_frame_size < max_frame &&
114              req->tp_frame_size < LIBTRACE_PACKET_BUFSIZE) {
115                req->tp_frame_size <<= 1;
116        }
117        if (req->tp_frame_size > LIBTRACE_PACKET_BUFSIZE)
118                req->tp_frame_size >>= 1;
119
120        /* Calculate block size */
121        req->tp_block_size = pagesize << max_order;
122        do {
123                req->tp_block_size >>= 1;
124        } while ((CONF_RING_FRAMES * req->tp_frame_size) <= req->tp_block_size);
125        req->tp_block_size <<= 1;
126
127        /* Calculate number of blocks */
128        req->tp_block_nr = (CONF_RING_FRAMES * req->tp_frame_size)
129                / req->tp_block_size;
130        if((CONF_RING_FRAMES * req->tp_frame_size) % req->tp_block_size != 0)
131                req->tp_block_nr++;
132
133        /* Calculate packets such that we use all the space we have to
134         * allocated */
135        req->tp_frame_nr = req->tp_block_nr *
136                (req->tp_block_size / req->tp_frame_size);
137
138        /*
139        printf("MaxO 0x%x BS 0x%x BN 0x%x FS 0x%x FN 0x%x\n",
140                max_order,
141                req->tp_block_size,
142                req->tp_block_nr,
143                req->tp_frame_size,
144                req->tp_frame_nr);
145        */
146
147        /* In case we have some silly values*/
148        assert(req->tp_block_size);
149        assert(req->tp_block_nr);
150        assert(req->tp_frame_size);
151        assert(req->tp_frame_nr);
152        assert(req->tp_block_size % req->tp_frame_size == 0);
153}
154
[6cf3ca0]155static inline int socket_to_packetmmap(char * uridata, int ring_type,
[1871afc]156                                        int fd,
157                                        struct tpacket_req * req,
158                                        char ** ring_location,
159                                        uint32_t *max_order,
160                                        char *error) {
161        int val;
162
163        /* Switch to TPACKET header version 2, we only try support v2 because
164         * v1 had problems with data type consistancy */
165        val = TPACKET_V2;
166        if (setsockopt(fd,
167                       SOL_PACKET,
168                       PACKET_VERSION,
169                       &val,
170                       sizeof(val)) == -1) {
171                strncpy(error, "TPACKET2 not supported", 2048);
172                return -1;
173        }
174
175        /* Try switch to a ring buffer. If it fails we assume the the kernel
176         * cannot allocate a block of that size, so decrease max_block and
177         * retry.
178         */
179        while(1) {
[6cf3ca0]180                fprintf(stderr, "max_order=%d\n", *max_order);
[1871afc]181                if (*max_order <= 0) {
182                        strncpy(error,
183                                "Cannot allocate enough memory for ring buffer",
184                                2048);
185                        return -1;
186                }
187                calculate_buffers(req, fd, uridata, *max_order);
188                if (setsockopt(fd,
189                               SOL_PACKET,
190                               ring_type,
191                               req,
192                               sizeof(struct tpacket_req)) == -1) {
193                        if(errno == ENOMEM) {
194                                (*max_order)--;
195                        } else {
196                                strncpy(error,
197                                        "Error setting the ring buffer size",
198                                        2048);
199                                return -1;
200                        }
201
202                } else break;
203        }
[6cf3ca0]204        fprintf(stderr, "max_order=%d\n", *max_order);
[1871afc]205
206        /* Map the ring buffer into userspace */
207        *ring_location = mmap(NULL,
208                              req->tp_block_size * req->tp_block_nr,
209                              PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
210        if(*ring_location == MAP_FAILED) {
211                strncpy(error, "Failed to map memory for ring buffer", 2048);
212                return -1;
213        }
214
215        return 0;
216}
217
218/* Release a frame back to the kernel or free() if it's a malloc'd buffer
219 */
[6cf3ca0]220inline static void ring_release_frame(libtrace_t *libtrace UNUSED,
[1871afc]221                                      libtrace_packet_t *packet)
222{
223        /* Free the old packet */
224        if(packet->buffer == NULL)
225                return;
226
227        if(packet->buf_control == TRACE_CTRL_PACKET){
228                free(packet->buffer);
229                packet->buffer = NULL;
230        }
231
232        if(packet->buf_control == TRACE_CTRL_EXTERNAL) {
[6cf3ca0]233                //struct linux_format_data_t *ftd = FORMAT_DATA;
[1871afc]234                /* Check it's within our buffer first - consider the pause
235                 * resume case it might have already been free'd lets hope we
236                 * get another buffer */
237                // TODO: For now let any one free anything
238                /*if(LIBTRACE_BETWEEN((char *) packet->buffer,
239                                (char *) ftd->rx_ring,
240                                ftd->rx_ring +
241                                ftd->req.tp_block_size *
242                                ftd->req.tp_block_nr)){*/
243                TO_TP_HDR2(packet->buffer)->tp_status = 0;
244                packet->buffer = NULL;
245                /*}*/
246        }
247}
248
[6cf3ca0]249static inline int linuxring_start_input_stream(libtrace_t *libtrace,
250                                               struct linux_per_stream_t *stream) {
[1871afc]251        char error[2048];
252
253        /* We set the socket up the same and then convert it to PACKET_MMAP */
[6cf3ca0]254        if (linuxcommon_start_input_stream(libtrace, stream) < 0)
[1871afc]255                return -1;
256
257        strncpy(error, "No known error", 2048);
258
259        /* Make it a packetmmap */
260        if(socket_to_packetmmap(libtrace->uridata, PACKET_RX_RING,
[6cf3ca0]261                                stream->fd,
262                                &FORMAT_DATA->req,
263                                &stream->rx_ring,
264                                &FORMAT_DATA->max_order,
265                                error) != 0) {
[1871afc]266                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
[6cf3ca0]267                              "Initialisation of packet MMAP failed: %s",
268                              error);
269                linuxcommon_close_input_stream(libtrace, stream);
[1871afc]270                return -1;
271        }
272
273        return 0;
274}
275
[6cf3ca0]276static int linuxring_start_input(libtrace_t *libtrace)
[1871afc]277{
[6cf3ca0]278        int ret = linuxring_start_input_stream(libtrace, FORMAT_DATA_FIRST);
279        if (ret != 0) {
280                libtrace_list_deinit(FORMAT_DATA->per_stream);
281                free(libtrace->format_data);
282                libtrace->format_data = NULL;
[1871afc]283        }
[6cf3ca0]284        return ret;
285}
[1871afc]286
[6cf3ca0]287static int linuxring_pstart_input(libtrace_t *libtrace) {
288        return linuxcommon_pstart_input(libtrace, linuxring_start_input_stream);
[1871afc]289}
290
291static int linuxring_start_output(libtrace_out_t *libtrace)
292{
293        char error[2048];
[6cf3ca0]294        FORMAT_DATA_OUT->fd = socket(PF_PACKET, SOCK_RAW, 0);
295        if (FORMAT_DATA_OUT->fd==-1) {
296                free(FORMAT_DATA_OUT);
297                trace_set_err_out(libtrace, errno, "Failed to create raw socket");
[1871afc]298                return -1;
[6cf3ca0]299        }
[1871afc]300
301        /* Make it a packetmmap */
302        if(socket_to_packetmmap(libtrace->uridata, PACKET_TX_RING,
303                                FORMAT_DATA_OUT->fd,
304                                &FORMAT_DATA_OUT->req,
305                                &FORMAT_DATA_OUT->tx_ring,
306                                &FORMAT_DATA_OUT->max_order,
307                                error) != 0) {
308                trace_set_err_out(libtrace, TRACE_ERR_INIT_FAILED,
309                                  "Initialisation of packet MMAP failed: %s",
310                                  error);
311                close(FORMAT_DATA_OUT->fd);
312                free(FORMAT_DATA_OUT);
313                libtrace->format_data = NULL;
314                return -1;
315        }
316
317        FORMAT_DATA_OUT->sock_hdr.sll_family = AF_PACKET;
318        FORMAT_DATA_OUT->sock_hdr.sll_protocol = 0;
319        FORMAT_DATA_OUT->sock_hdr.sll_ifindex =
320                if_nametoindex(libtrace->uridata);
321        FORMAT_DATA_OUT->sock_hdr.sll_hatype = 0;
322        FORMAT_DATA_OUT->sock_hdr.sll_pkttype = 0;
323        FORMAT_DATA_OUT->sock_hdr.sll_halen = 0;
324        FORMAT_DATA_OUT->queue = 0;
325
326        return 0;
327}
328
329static int linuxring_fin_output(libtrace_out_t *libtrace)
330{
331        /* Make sure any remaining frames get sent */
332        sendto(FORMAT_DATA_OUT->fd,
333               NULL,
334               0,
335               0,
336               (void *) &FORMAT_DATA_OUT->sock_hdr,
337               sizeof(FORMAT_DATA_OUT->sock_hdr));
338
339        /* Unmap our data area */
340        munmap(FORMAT_DATA_OUT->tx_ring,
341               FORMAT_DATA_OUT->req.tp_block_size *
342               FORMAT_DATA_OUT->req.tp_block_nr);
343
[6cf3ca0]344        /* Free the socket */
345        close(FORMAT_DATA_OUT->fd);
346        FORMAT_DATA_OUT->fd=-1;
347        free(libtrace->format_data);
348        return 0;
[1871afc]349}
350
[6cf3ca0]351static libtrace_linktype_t
352linuxring_get_link_type(const struct libtrace_packet_t *packet)
[1871afc]353{
[6cf3ca0]354        uint16_t linktype = GET_SOCKADDR_HDR(packet->buffer)->sll_hatype;
355        return linuxcommon_get_link_type(linktype);
[1871afc]356}
357
[6cf3ca0]358static libtrace_direction_t
359linuxring_get_direction(const struct libtrace_packet_t *packet) {
360        return linuxcommon_get_direction(GET_SOCKADDR_HDR(packet->buffer)->
361                                         sll_pkttype);
362}
363
364static libtrace_direction_t
365linuxring_set_direction(libtrace_packet_t *packet,
366                        libtrace_direction_t direction) {
367        return linuxcommon_set_direction(GET_SOCKADDR_HDR(packet->buffer), direction);
368}
369
370static struct timeval linuxring_get_timeval(const libtrace_packet_t *packet)
[1871afc]371{
[6cf3ca0]372        struct timeval tv;
373        tv.tv_sec = TO_TP_HDR2(packet->buffer)->tp_sec;
374        tv.tv_usec = TO_TP_HDR2(packet->buffer)->tp_nsec / 1000;
375        return tv;
[1871afc]376}
377
[6cf3ca0]378static struct timespec linuxring_get_timespec(const libtrace_packet_t *packet)
379{
380        struct timespec ts;
381        ts.tv_sec = TO_TP_HDR2(packet->buffer)->tp_sec;
382        ts.tv_nsec = TO_TP_HDR2(packet->buffer)->tp_nsec;
383        return ts;
384}
385
386static int linuxring_get_capture_length(const libtrace_packet_t *packet)
387{
388        return TO_TP_HDR2(packet->buffer)->tp_snaplen;
389}
390
391static int linuxring_get_wire_length(const libtrace_packet_t *packet)
392{
393        int wirelen = TO_TP_HDR2(packet->buffer)->tp_len;
394
395        /* Include the missing FCS */
396        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
397                wirelen += 4;
398
399        return wirelen;
400}
401
402static int linuxring_get_framing_length(const libtrace_packet_t *packet)
403{
404        /*
405         * Need to make frame_length + capture_length = complete capture length
406         * so include alignment whitespace. So reverse calculate from packet.
407         */
408        return (char *)packet->payload - (char *)packet->buffer;
409}
410
411static size_t linuxring_set_capture_length(libtrace_packet_t *packet,
412                                           size_t size)
413{
414        assert(packet);
415        if (size > trace_get_capture_length(packet)) {
416                /* We should avoid making a packet larger */
417                return trace_get_capture_length(packet);
418        }
419
420        /* Reset the cached capture length */
421        packet->capture_length = -1;
422
423        TO_TP_HDR2(packet->buffer)->tp_snaplen = size;
424
425        return trace_get_capture_length(packet);
426}
427
428static int linuxring_prepare_packet(libtrace_t *libtrace UNUSED,
429                                    libtrace_packet_t *packet, void *buffer,
430                                    libtrace_rt_types_t rt_type, uint32_t flags)
431{
432        if (packet->buffer != buffer &&
433            packet->buf_control == TRACE_CTRL_PACKET) {
434                free(packet->buffer);
435        }
436
437        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER)
438                packet->buf_control = TRACE_CTRL_PACKET;
439        else
440                packet->buf_control = TRACE_CTRL_EXTERNAL;
441
442
443        packet->buffer = buffer;
444        packet->header = buffer;
445        packet->payload = (char *)buffer +
446                TP_TRACE_START(TO_TP_HDR2(packet->header)->tp_mac,
447                               TO_TP_HDR2(packet->header)->tp_net,
448                               TPACKET2_HDRLEN);
449        packet->type = rt_type;
450
451        return 0;
452}
453#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
454inline static int linuxring_read_stream(libtrace_t *libtrace,
455                                        libtrace_packet_t *packet,
456                                        struct linux_per_stream_t *stream,
457                                        libtrace_message_queue_t *queue) {
[1871afc]458
459        struct tpacket2_hdr *header;
460        int ret;
461        unsigned int snaplen;
[6cf3ca0]462        struct pollfd pollset[2];
463
[1871afc]464        ring_release_frame(libtrace, packet);
465       
466        packet->buf_control = TRACE_CTRL_EXTERNAL;
467        packet->type = TRACE_RT_DATA_LINUX_RING;
468       
469        /* Fetch the current frame */
[6cf3ca0]470        header = GET_CURRENT_BUFFER(libtrace, stream);
[1871afc]471        assert((((unsigned long) header) & (pagesize - 1)) == 0);
472
473        /* TP_STATUS_USER means that we can use the frame.
474         * When a slot does not have this flag set, the frame is not
475         * ready for consumption.
476         */
477        while (!(header->tp_status & TP_STATUS_USER)) {
[6cf3ca0]478                pollset[0].fd = stream->fd;
479                pollset[0].events = POLLIN;
480                pollset[0].revents = 0;
481                if (queue) {
482                        pollset[1].fd = libtrace_message_queue_get_fd(queue);
[1871afc]483                        pollset[1].events = POLLIN;
484                        pollset[1].revents = 0;
[6cf3ca0]485                }
[1ebc4bd]486                /* Wait for more data or a message */
487                ret = poll(pollset, (queue ? 2 : 1), 500);
[6cf3ca0]488                if (ret > 0) {
[1ebc4bd]489                        if (pollset[0].revents == POLLIN)
[1871afc]490                                continue;
[1ebc4bd]491                        else if (queue && pollset[1].revents == POLLIN)
[6cf3ca0]492                                return READ_MESSAGE;
[1ebc4bd]493                        else if (queue && pollset[1].revents) {
494                                /* Internal error */
495                                trace_set_err(libtrace,TRACE_ERR_BAD_STATE,
496                                              "Message queue error %d poll()",
497                                              pollset[1].revents);
498                                return READ_ERROR;
499                        } else {
[3e89670]500                                /* Try get the error from the socket */
501                                int err = ENETDOWN;
502                                socklen_t len = sizeof(err);
503                                getsockopt(stream->fd, SOL_SOCKET, SO_ERROR,
504                                           &err, &len);
505                                trace_set_err(libtrace, err,
[1ebc4bd]506                                              "Socket error revents=%d poll()",
507                                              pollset[0].revents);
508                                return READ_ERROR;
509                        }
[6cf3ca0]510                } else if (ret < 0) {
[1ebc4bd]511                        if (errno != EINTR) {
512                                trace_set_err(libtrace,errno,"poll()");
513                                return -1;
514                        }
[6cf3ca0]515                } else {
516                        /* Poll timed out - check if we should exit */
517                        if (libtrace_halt)
518                                return 0;
519                        continue;
[1871afc]520                }
521        }
522
523        packet->buffer = header;
524
525        /* If a snaplen was configured, automatically truncate the packet to
526         * the desired length.
527         */
528        snaplen=LIBTRACE_MIN(
529                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*header),
[6cf3ca0]530                        (int)FORMAT_DATA->snaplen);
[1871afc]531       
532        TO_TP_HDR2(packet->buffer)->tp_snaplen = LIBTRACE_MIN((unsigned int)snaplen, TO_TP_HDR2(packet->buffer)->tp_len);
533
534        /* Move to next buffer */
[6cf3ca0]535        stream->rxring_offset++;
536        stream->rxring_offset %= FORMAT_DATA->req.tp_frame_nr;
[1871afc]537
538        /* We just need to get prepare_packet to set all our packet pointers
539         * appropriately */
540        if (linuxring_prepare_packet(libtrace, packet, packet->buffer,
541                                packet->type, 0))
542                return -1;
543        return  linuxring_get_framing_length(packet) + 
544                                linuxring_get_capture_length(packet);
545
546}
547
548static int linuxring_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
[6cf3ca0]549        return linuxring_read_stream(libtrace, packet, FORMAT_DATA_FIRST, NULL);
[1871afc]550}
551
552static int linuxring_pread_packets(libtrace_t *libtrace,
553                                   libtrace_thread_t *t,
[6cf3ca0]554                                   libtrace_packet_t *packets[],
[1871afc]555                                   UNUSED size_t nb_packets) {
[6cf3ca0]556        /* For now just read one packet */
557        packets[0]->error = linuxring_read_stream(libtrace, packets[0],
558                                                  t->format_data, &t->messages);
[1871afc]559        if (packets[0]->error >= 1)
560                return 1;
561        else
562                return packets[0]->error;
563}
564
565/* Non-blocking read */
566static libtrace_eventobj_t linuxring_event(libtrace_t *libtrace,
567                                           libtrace_packet_t *packet)
568{
569        struct tpacket2_hdr *header;
570        libtrace_eventobj_t event = {0,0,0.0,0};
571
572        /* We must free the old packet, otherwise select() will instantly
573         * return */
574        ring_release_frame(libtrace, packet);
575
576        /* Fetch the current frame */
[6cf3ca0]577        header = GET_CURRENT_BUFFER(libtrace, FORMAT_DATA_FIRST);
[1871afc]578        if (header->tp_status & TP_STATUS_USER) {
579                /* We have a frame waiting */
580                event.size = trace_read_packet(libtrace, packet);
581                event.type = TRACE_EVENT_PACKET;
582        } else {
583                /* Ok we don't have a packet waiting */
584                event.type = TRACE_EVENT_IOWAIT;
585                event.fd = FORMAT_DATA_FIRST->fd;
586        }
587
588        return event;
589}
590
591/**
592 * Free any resources being kept for this packet, Note: libtrace
593 * will ensure all fields are zeroed correctly.
594 */
595static void linuxring_fin_packet(libtrace_packet_t *packet)
596{
597        libtrace_t *libtrace = packet->trace;
598
599        if (packet->buffer == NULL)
600                return;
601        assert(packet->trace);
602
603        /* If we own the packet (i.e. it's not a copy), we need to free it */
604        if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
[6cf3ca0]605                /* Started should always match the existence of the rx_ring
606                 * in the parallel case still just check the first ring */
[1871afc]607                assert(!!FORMAT_DATA_FIRST->rx_ring ==
608                       !!packet->trace->started);
609                /* If we don't have a ring its already been destroyed */
[6cf3ca0]610                if (FORMAT_DATA_FIRST->rx_ring != MAP_FAILED)
[1871afc]611                        ring_release_frame(packet->trace, packet);
612                else
613                        packet->buffer = NULL;
614        }
615}
616
617static int linuxring_write_packet(libtrace_out_t *libtrace,
618                                  libtrace_packet_t *packet)
619{
620        struct tpacket2_hdr *header;
621        struct pollfd pollset;
622        struct socket_addr;
623        int ret;
624        unsigned max_size;
625        void * off;
626
627        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
628                return 0;
629
630        max_size = FORMAT_DATA_OUT->req.tp_frame_size -
631                TPACKET2_HDRLEN + sizeof(struct sockaddr_ll);
632
633        header = (void *)FORMAT_DATA_OUT->tx_ring +
634                (FORMAT_DATA_OUT->txring_offset *
635                 FORMAT_DATA_OUT->req.tp_frame_size);
636
637        while(header->tp_status != TP_STATUS_AVAILABLE) {
638                /* if none available: wait on more data */
639                pollset.fd = FORMAT_DATA_OUT->fd;
640                pollset.events = POLLOUT;
641                pollset.revents = 0;
642                ret = poll(&pollset, 1, 1000);
643                if (ret < 0 && errno != EINTR) {
644                        perror("poll");
645                        return -1;
646                }
647                if(ret == 0)
648                        /* Timeout something has gone wrong - maybe the queue is
649                         * to large so try issue another send command
650                         */
651                        ret = sendto(FORMAT_DATA_OUT->fd,
652                                     NULL,
653                                     0,
654                                     0,
655                                     (void *)&FORMAT_DATA_OUT->sock_hdr,
656                                     sizeof(FORMAT_DATA_OUT->sock_hdr));
657                        if (ret < 0) {
658                                trace_set_err_out(libtrace, errno,
659                                                  "sendto after timeout "
660                                                  "failed");
661                                return -1;
662                        }
663        }
664
665        header->tp_len = trace_get_capture_length(packet);
666
667        /* We cannot write the whole packet so just write part of it */
668        if (header->tp_len > max_size)
669                header->tp_len = max_size;
670
671        /* Fill packet - no sockaddr_ll in header when writing to the TX_RING */
672        off = ((void *)header) + (TPACKET2_HDRLEN - sizeof(struct sockaddr_ll));
673        memcpy(off, (char *)packet->payload, header->tp_len);
674
675        /* 'Send it' and increase ring pointer to the next frame */
676        header->tp_status = TP_STATUS_SEND_REQUEST;
677        FORMAT_DATA_OUT->txring_offset = (FORMAT_DATA_OUT->txring_offset + 1) %
678                FORMAT_DATA_OUT->req.tp_frame_nr;
679
680        /* Notify kernel there are frames to send */
681        FORMAT_DATA_OUT->queue ++;
682        FORMAT_DATA_OUT->queue %= TX_MAX_QUEUE;
683        if(FORMAT_DATA_OUT->queue == 0){
684                ret = sendto(FORMAT_DATA_OUT->fd,
685                                NULL,
686                                0,
687                                MSG_DONTWAIT,
688                                (void *)&FORMAT_DATA_OUT->sock_hdr,
689                                sizeof(FORMAT_DATA_OUT->sock_hdr));
690                if (ret < 0) {
691                        trace_set_err_out(libtrace, errno, "sendto failed");
692                        return -1;
693                }
694        }
695        return header->tp_len;
696
697}
698
699#ifdef HAVE_NETPACKET_PACKET_H
700
701static void linuxring_help(void)
702{
703        printf("linuxring format module: $Revision: 1793 $\n");
704        printf("Supported input URIs:\n");
705        printf("\tring:eth0\n");
706        printf("\n");
707        printf("Supported output URIs:\n");
708        printf("\tring:eth0\n");
709        printf("\n");
710        return;
711}
712
713static struct libtrace_format_t linuxring = {
714        "ring",
715        "$Id$",
716        TRACE_FORMAT_LINUX_RING,
[6cf3ca0]717        linuxcommon_probe_filename,     /* probe filename */
[1871afc]718        NULL,                           /* probe magic */
[6cf3ca0]719        linuxcommon_init_input,         /* init_input */
720        linuxcommon_config_input,       /* config_input */
[1871afc]721        linuxring_start_input,          /* start_input */
[6cf3ca0]722        linuxcommon_pause_input,        /* pause_input */
723        linuxcommon_init_output,        /* init_output */
[1871afc]724        NULL,                           /* config_output */
725        linuxring_start_output,         /* start_ouput */
[6cf3ca0]726        linuxcommon_fin_input,          /* fin_input */
[1871afc]727        linuxring_fin_output,           /* fin_output */
728        linuxring_read_packet,          /* read_packet */
729        linuxring_prepare_packet,       /* prepare_packet */
730        linuxring_fin_packet,           /* fin_packet */
731        linuxring_write_packet,         /* write_packet */
732        linuxring_get_link_type,        /* get_link_type */
733        linuxring_get_direction,        /* get_direction */
734        linuxring_set_direction,        /* set_direction */
735        NULL,                           /* get_erf_timestamp */
736        linuxring_get_timeval,          /* get_timeval */
737        linuxring_get_timespec,         /* get_timespec */
738        NULL,                           /* get_seconds */
739        NULL,                           /* seek_erf */
740        NULL,                           /* seek_timeval */
741        NULL,                           /* seek_seconds */
742        linuxring_get_capture_length,   /* get_capture_length */
743        linuxring_get_wire_length,      /* get_wire_length */
744        linuxring_get_framing_length,   /* get_framing_length */
745        linuxring_set_capture_length,   /* set_capture_length */
746        NULL,                           /* get_received_packets */
[5ab626a]747        NULL,                           /* get_filtered_packets */
748        NULL,                           /* get_dropped_packets */
749        linuxcommon_get_statistics,     /* get_statistics */
[6cf3ca0]750        linuxcommon_get_fd,             /* get_fd */
[1871afc]751        linuxring_event,                /* trace_event */
[6cf3ca0]752        linuxring_help,                 /* help */
[1871afc]753        NULL,                           /* next pointer */
754        {true, -1},                     /* Live, no thread limit */
[6cf3ca0]755        linuxring_pstart_input,         /* pstart_input */
[1871afc]756        linuxring_pread_packets,        /* pread_packets */
[6cf3ca0]757        linuxcommon_pause_input,        /* ppause */
758        linuxcommon_fin_input,          /* p_fin */
[5ab626a]759        linuxcommon_pconfig_input,      /* pconfig input */
760        linuxcommon_pregister_thread,   /* register thread */
761        NULL,                           /* unregister thread */
762        NULL                            /* get thread stats */
[1871afc]763};
764#else
765
766static void linuxring_help(void)
767{
768        printf("linuxring format module: $Revision: 1793 $\n");
769        printf("Not supported on this host\n");
770}
771
772static struct libtrace_format_t linuxring = {
773        "ring",
774        "$Id$",
775        TRACE_FORMAT_LINUX_RING,
776        NULL,                           /* probe filename */
777        NULL,                           /* probe magic */
778        NULL,                           /* init_input */
779        NULL,                           /* config_input */
780        NULL,                           /* start_input */
781        NULL,                           /* pause_input */
782        NULL,                           /* init_output */
783        NULL,                           /* config_output */
784        NULL,                           /* start_ouput */
785        NULL,                           /* fin_input */
786        NULL,                           /* fin_output */
787        NULL,                           /* read_packet */
788        linuxring_prepare_packet,       /* prepare_packet */
789        NULL,                           /* fin_packet */
790        NULL,                           /* write_packet */
791        linuxring_get_link_type,        /* get_link_type */
792        linuxring_get_direction,        /* get_direction */
793        linuxring_set_direction,        /* set_direction */
794        NULL,                           /* get_erf_timestamp */
795        linuxring_get_timeval,          /* get_timeval */
796        linuxring_get_timespec,         /* get_timespec */
797        NULL,                           /* get_seconds */
798        NULL,                           /* seek_erf */
799        NULL,                           /* seek_timeval */
800        NULL,                           /* seek_seconds */
801        linuxring_get_capture_length,   /* get_capture_length */
802        linuxring_get_wire_length,      /* get_wire_length */
803        linuxring_get_framing_length,   /* get_framing_length */
804        linuxring_set_capture_length,   /* set_capture_length */
805        NULL,                           /* get_received_packets */
806        NULL,                           /* get_filtered_packets */
807        NULL,                           /* get_dropped_packets */
[5ab626a]808        linuxcommon_get_statistics,     /* get_statistics */
[1871afc]809        NULL,                           /* get_fd */
810        NULL,                           /* trace_event */
811        linuxring_help,                 /* help */
812        NULL,                           /* next pointer */
813        NON_PARALLEL(true)
814};
815#endif
816
817/* TODO: Figure out how to give this format preference over the linux native
818 * formate if the user only specifies an interface */
819void linuxring_constructor(void)
820{
821        register_format(&linuxring);
822}
Note: See TracBrowser for help on using the repository browser.