source: lib/format_linux_ring.c @ 9a6bdbc

develop
Last change on this file since 9a6bdbc was 9a6bdbc, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

Added can_write functions to each output format, Fixed pcapng_get_header_type incorrectly flipping type bytes

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