source: lib/format_linux_ring.c @ 1e6d795

develop
Last change on this file since 1e6d795 was 1e6d795, checked in by Shane Alcock <salcock@…>, 2 years ago

Remove hard-coded limit of 1 for ring burst size.

This no longer applies given that we (in theory) support multiple
packets per read.

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