source: lib/format_linux_ring.c @ d7d3267

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

Merge branch 'master' of git://github.com/jacobvw/libtrace into jacobvw-master

Conflicts:

lib/format_linux_ring.c

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