source: lib/format_linux_ring.c @ 1ebc4bd

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

Fix bug in ring: format if the interface is down

If the ring interface goes down (or starts down), Linux considers this
to be an error for the socket and we were not checking for the error
returns of the individual poll() items, where this error was returned.

Due to ordering of the code this broke libtrace_halt (if no packets are being received),
even if the interface came back (once shutdown the error seems to persist
upon restart).

The behaviour now is that an error, such as the interface being down
(probably the only error one could encounter?) will return as an error
to the libtrace application.

  • Property mode set to 100644
File size: 23.6 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_common.h"
64
65#ifdef HAVE_NETPACKET_PACKET_H
66/* Get current frame in the ring buffer*/
67#define GET_CURRENT_BUFFER(libtrace, stream) \
68        ((void *)stream->rx_ring +                              \
69         (stream->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/* Cached page size, the page size shouldn't be changing */
79static int pagesize = 0;
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
155static inline int socket_to_packetmmap(char * uridata, int ring_type,
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) {
180                fprintf(stderr, "max_order=%d\n", *max_order);
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        }
204        fprintf(stderr, "max_order=%d\n", *max_order);
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 */
220inline static void ring_release_frame(libtrace_t *libtrace UNUSED,
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) {
233                //struct linux_format_data_t *ftd = FORMAT_DATA;
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
249static inline int linuxring_start_input_stream(libtrace_t *libtrace,
250                                               struct linux_per_stream_t *stream) {
251        char error[2048];
252
253        /* We set the socket up the same and then convert it to PACKET_MMAP */
254        if (linuxcommon_start_input_stream(libtrace, stream) < 0)
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,
261                                stream->fd,
262                                &FORMAT_DATA->req,
263                                &stream->rx_ring,
264                                &FORMAT_DATA->max_order,
265                                error) != 0) {
266                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
267                              "Initialisation of packet MMAP failed: %s",
268                              error);
269                linuxcommon_close_input_stream(libtrace, stream);
270                return -1;
271        }
272
273        return 0;
274}
275
276static int linuxring_start_input(libtrace_t *libtrace)
277{
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;
283        }
284        return ret;
285}
286
287static int linuxring_pstart_input(libtrace_t *libtrace) {
288        return linuxcommon_pstart_input(libtrace, linuxring_start_input_stream);
289}
290
291static int linuxring_start_output(libtrace_out_t *libtrace)
292{
293        char error[2048];
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");
298                return -1;
299        }
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
344        /* Free the socket */
345        close(FORMAT_DATA_OUT->fd);
346        FORMAT_DATA_OUT->fd=-1;
347        free(libtrace->format_data);
348        return 0;
349}
350
351static libtrace_linktype_t
352linuxring_get_link_type(const struct libtrace_packet_t *packet)
353{
354        uint16_t linktype = GET_SOCKADDR_HDR(packet->buffer)->sll_hatype;
355        return linuxcommon_get_link_type(linktype);
356}
357
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)
371{
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;
376}
377
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) {
458
459        struct tpacket2_hdr *header;
460        int ret;
461        unsigned int snaplen;
462        struct pollfd pollset[2];
463
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 */
470        header = GET_CURRENT_BUFFER(libtrace, stream);
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)) {
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);
483                        pollset[1].events = POLLIN;
484                        pollset[1].revents = 0;
485                }
486                /* Wait for more data or a message */
487                ret = poll(pollset, (queue ? 2 : 1), 500);
488                if (ret > 0) {
489                        if (pollset[0].revents == POLLIN)
490                                continue;
491                        else if (queue && pollset[1].revents == POLLIN)
492                                return READ_MESSAGE;
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 {
500                                /* I've only seen this when the network was down */
501                                trace_set_err(libtrace,ENETDOWN,
502                                              "Socket error revents=%d poll()",
503                                              pollset[0].revents);
504                                return READ_ERROR;
505                        }
506                } else if (ret < 0) {
507                        if (errno != EINTR) {
508                                trace_set_err(libtrace,errno,"poll()");
509                                return -1;
510                        }
511                } else {
512                        /* Poll timed out - check if we should exit */
513                        if (libtrace_halt)
514                                return 0;
515                        continue;
516                }
517        }
518
519        packet->buffer = header;
520
521        /* If a snaplen was configured, automatically truncate the packet to
522         * the desired length.
523         */
524        snaplen=LIBTRACE_MIN(
525                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*header),
526                        (int)FORMAT_DATA->snaplen);
527       
528        TO_TP_HDR2(packet->buffer)->tp_snaplen = LIBTRACE_MIN((unsigned int)snaplen, TO_TP_HDR2(packet->buffer)->tp_len);
529
530        /* Move to next buffer */
531        stream->rxring_offset++;
532        stream->rxring_offset %= FORMAT_DATA->req.tp_frame_nr;
533
534        /* We just need to get prepare_packet to set all our packet pointers
535         * appropriately */
536        if (linuxring_prepare_packet(libtrace, packet, packet->buffer,
537                                packet->type, 0))
538                return -1;
539        return  linuxring_get_framing_length(packet) + 
540                                linuxring_get_capture_length(packet);
541
542}
543
544static int linuxring_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
545        return linuxring_read_stream(libtrace, packet, FORMAT_DATA_FIRST, NULL);
546}
547
548static int linuxring_pread_packets(libtrace_t *libtrace,
549                                   libtrace_thread_t *t,
550                                   libtrace_packet_t *packets[],
551                                   UNUSED size_t nb_packets) {
552        /* For now just read one packet */
553        packets[0]->error = linuxring_read_stream(libtrace, packets[0],
554                                                  t->format_data, &t->messages);
555        if (packets[0]->error >= 1)
556                return 1;
557        else
558                return packets[0]->error;
559}
560
561/* Non-blocking read */
562static libtrace_eventobj_t linuxring_event(libtrace_t *libtrace,
563                                           libtrace_packet_t *packet)
564{
565        struct tpacket2_hdr *header;
566        libtrace_eventobj_t event = {0,0,0.0,0};
567
568        /* We must free the old packet, otherwise select() will instantly
569         * return */
570        ring_release_frame(libtrace, packet);
571
572        /* Fetch the current frame */
573        header = GET_CURRENT_BUFFER(libtrace, FORMAT_DATA_FIRST);
574        if (header->tp_status & TP_STATUS_USER) {
575                /* We have a frame waiting */
576                event.size = trace_read_packet(libtrace, packet);
577                event.type = TRACE_EVENT_PACKET;
578        } else {
579                /* Ok we don't have a packet waiting */
580                event.type = TRACE_EVENT_IOWAIT;
581                event.fd = FORMAT_DATA_FIRST->fd;
582        }
583
584        return event;
585}
586
587/**
588 * Free any resources being kept for this packet, Note: libtrace
589 * will ensure all fields are zeroed correctly.
590 */
591static void linuxring_fin_packet(libtrace_packet_t *packet)
592{
593        libtrace_t *libtrace = packet->trace;
594
595        if (packet->buffer == NULL)
596                return;
597        assert(packet->trace);
598
599        /* If we own the packet (i.e. it's not a copy), we need to free it */
600        if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
601                /* Started should always match the existence of the rx_ring
602                 * in the parallel case still just check the first ring */
603                assert(!!FORMAT_DATA_FIRST->rx_ring ==
604                       !!packet->trace->started);
605                /* If we don't have a ring its already been destroyed */
606                if (FORMAT_DATA_FIRST->rx_ring != MAP_FAILED)
607                        ring_release_frame(packet->trace, packet);
608                else
609                        packet->buffer = NULL;
610        }
611}
612
613static int linuxring_write_packet(libtrace_out_t *libtrace,
614                                  libtrace_packet_t *packet)
615{
616        struct tpacket2_hdr *header;
617        struct pollfd pollset;
618        struct socket_addr;
619        int ret;
620        unsigned max_size;
621        void * off;
622
623        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
624                return 0;
625
626        max_size = FORMAT_DATA_OUT->req.tp_frame_size -
627                TPACKET2_HDRLEN + sizeof(struct sockaddr_ll);
628
629        header = (void *)FORMAT_DATA_OUT->tx_ring +
630                (FORMAT_DATA_OUT->txring_offset *
631                 FORMAT_DATA_OUT->req.tp_frame_size);
632
633        while(header->tp_status != TP_STATUS_AVAILABLE) {
634                /* if none available: wait on more data */
635                pollset.fd = FORMAT_DATA_OUT->fd;
636                pollset.events = POLLOUT;
637                pollset.revents = 0;
638                ret = poll(&pollset, 1, 1000);
639                if (ret < 0 && errno != EINTR) {
640                        perror("poll");
641                        return -1;
642                }
643                if(ret == 0)
644                        /* Timeout something has gone wrong - maybe the queue is
645                         * to large so try issue another send command
646                         */
647                        ret = sendto(FORMAT_DATA_OUT->fd,
648                                     NULL,
649                                     0,
650                                     0,
651                                     (void *)&FORMAT_DATA_OUT->sock_hdr,
652                                     sizeof(FORMAT_DATA_OUT->sock_hdr));
653                        if (ret < 0) {
654                                trace_set_err_out(libtrace, errno,
655                                                  "sendto after timeout "
656                                                  "failed");
657                                return -1;
658                        }
659        }
660
661        header->tp_len = trace_get_capture_length(packet);
662
663        /* We cannot write the whole packet so just write part of it */
664        if (header->tp_len > max_size)
665                header->tp_len = max_size;
666
667        /* Fill packet - no sockaddr_ll in header when writing to the TX_RING */
668        off = ((void *)header) + (TPACKET2_HDRLEN - sizeof(struct sockaddr_ll));
669        memcpy(off, (char *)packet->payload, header->tp_len);
670
671        /* 'Send it' and increase ring pointer to the next frame */
672        header->tp_status = TP_STATUS_SEND_REQUEST;
673        FORMAT_DATA_OUT->txring_offset = (FORMAT_DATA_OUT->txring_offset + 1) %
674                FORMAT_DATA_OUT->req.tp_frame_nr;
675
676        /* Notify kernel there are frames to send */
677        FORMAT_DATA_OUT->queue ++;
678        FORMAT_DATA_OUT->queue %= TX_MAX_QUEUE;
679        if(FORMAT_DATA_OUT->queue == 0){
680                ret = sendto(FORMAT_DATA_OUT->fd,
681                                NULL,
682                                0,
683                                MSG_DONTWAIT,
684                                (void *)&FORMAT_DATA_OUT->sock_hdr,
685                                sizeof(FORMAT_DATA_OUT->sock_hdr));
686                if (ret < 0) {
687                        trace_set_err_out(libtrace, errno, "sendto failed");
688                        return -1;
689                }
690        }
691        return header->tp_len;
692
693}
694
695#ifdef HAVE_NETPACKET_PACKET_H
696
697static void linuxring_help(void)
698{
699        printf("linuxring format module: $Revision: 1793 $\n");
700        printf("Supported input URIs:\n");
701        printf("\tring:eth0\n");
702        printf("\n");
703        printf("Supported output URIs:\n");
704        printf("\tring:eth0\n");
705        printf("\n");
706        return;
707}
708
709static struct libtrace_format_t linuxring = {
710        "ring",
711        "$Id$",
712        TRACE_FORMAT_LINUX_RING,
713        linuxcommon_probe_filename,     /* probe filename */
714        NULL,                           /* probe magic */
715        linuxcommon_init_input,         /* init_input */
716        linuxcommon_config_input,       /* config_input */
717        linuxring_start_input,          /* start_input */
718        linuxcommon_pause_input,        /* pause_input */
719        linuxcommon_init_output,        /* init_output */
720        NULL,                           /* config_output */
721        linuxring_start_output,         /* start_ouput */
722        linuxcommon_fin_input,          /* fin_input */
723        linuxring_fin_output,           /* fin_output */
724        linuxring_read_packet,          /* read_packet */
725        linuxring_prepare_packet,       /* prepare_packet */
726        linuxring_fin_packet,           /* fin_packet */
727        linuxring_write_packet,         /* write_packet */
728        linuxring_get_link_type,        /* get_link_type */
729        linuxring_get_direction,        /* get_direction */
730        linuxring_set_direction,        /* set_direction */
731        NULL,                           /* get_erf_timestamp */
732        linuxring_get_timeval,          /* get_timeval */
733        linuxring_get_timespec,         /* get_timespec */
734        NULL,                           /* get_seconds */
735        NULL,                           /* seek_erf */
736        NULL,                           /* seek_timeval */
737        NULL,                           /* seek_seconds */
738        linuxring_get_capture_length,   /* get_capture_length */
739        linuxring_get_wire_length,      /* get_wire_length */
740        linuxring_get_framing_length,   /* get_framing_length */
741        linuxring_set_capture_length,   /* set_capture_length */
742        NULL,                           /* get_received_packets */
743        linuxcommon_get_filtered_packets,/* get_filtered_packets */
744        linuxcommon_get_dropped_packets,/* get_dropped_packets */
745        linuxcommon_get_captured_packets,/* get_captured_packets */
746        linuxcommon_get_fd,             /* get_fd */
747        linuxring_event,                /* trace_event */
748        linuxring_help,                 /* help */
749        NULL,                           /* next pointer */
750        {true, -1},                     /* Live, no thread limit */
751        linuxring_pstart_input,         /* pstart_input */
752        linuxring_pread_packets,        /* pread_packets */
753        linuxcommon_pause_input,        /* ppause */
754        linuxcommon_fin_input,          /* p_fin */
755        linuxcommon_pconfig_input,      /* pconfig input */
756        linuxcommon_pregister_thread,
757        NULL
758};
759#else
760
761static void linuxring_help(void)
762{
763        printf("linuxring format module: $Revision: 1793 $\n");
764        printf("Not supported on this host\n");
765}
766
767static struct libtrace_format_t linuxring = {
768        "ring",
769        "$Id$",
770        TRACE_FORMAT_LINUX_RING,
771        NULL,                           /* probe filename */
772        NULL,                           /* probe magic */
773        NULL,                           /* init_input */
774        NULL,                           /* config_input */
775        NULL,                           /* start_input */
776        NULL,                           /* pause_input */
777        NULL,                           /* init_output */
778        NULL,                           /* config_output */
779        NULL,                           /* start_ouput */
780        NULL,                           /* fin_input */
781        NULL,                           /* fin_output */
782        NULL,                           /* read_packet */
783        linuxring_prepare_packet,       /* prepare_packet */
784        NULL,                           /* fin_packet */
785        NULL,                           /* write_packet */
786        linuxring_get_link_type,        /* get_link_type */
787        linuxring_get_direction,        /* get_direction */
788        linuxring_set_direction,        /* set_direction */
789        NULL,                           /* get_erf_timestamp */
790        linuxring_get_timeval,          /* get_timeval */
791        linuxring_get_timespec,         /* get_timespec */
792        NULL,                           /* get_seconds */
793        NULL,                           /* seek_erf */
794        NULL,                           /* seek_timeval */
795        NULL,                           /* seek_seconds */
796        linuxring_get_capture_length,   /* get_capture_length */
797        linuxring_get_wire_length,      /* get_wire_length */
798        linuxring_get_framing_length,   /* get_framing_length */
799        linuxring_set_capture_length,   /* set_capture_length */
800        NULL,                           /* get_received_packets */
801        NULL,                           /* get_filtered_packets */
802        NULL,                           /* get_dropped_packets */
803        NULL,                           /* get_captured_packets */
804        NULL,                           /* get_fd */
805        NULL,                           /* trace_event */
806        linuxring_help,                 /* help */
807        NULL,                           /* next pointer */
808        NON_PARALLEL(true)
809};
810#endif
811
812/* TODO: Figure out how to give this format preference over the linux native
813 * formate if the user only specifies an interface */
814void linuxring_constructor(void)
815{
816        register_format(&linuxring);
817}
Note: See TracBrowser for help on using the repository browser.