source: lib/format_linux_int.c @ 6cf3ca0

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

Gets the ring format back to a working state, the bulk of the refactoring
is now done.

I've opted to remove the inheritance way of grabbing shared functions
and replaced it with a file containing the common functions. Hopefully
this is more obvious that both int and ring depend on these.

I've also reworked the formats to be stream orientated, which removed
duplicates of heaps of functions. And allows the parallel and single
thread code to be almost identical.

After doing this many of the places where we had differences in
functions between ring and int disappeared.

I've also upped the MAX_ORDER to 11, used in allocating memory
from the kernel for the ring format.
Since this seems to work on the testing machines.
And we'll continue to fallback to smaller values if needed anyway.

  • Property mode set to 100644
File size: 16.4 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *          Richard Sanger
11 *         
12 * All rights reserved.
13 *
14 * This code has been developed by the University of Waikato WAND
15 * research group. For further information please see http://www.wand.net.nz/
16 *
17 * libtrace is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * libtrace is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with libtrace; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30 *
31 * $Id$
32 *
33 */
34
35/* This format module deals with using the Linux Native capture format.
36 *
37 * Linux Native is a LIVE capture format.
38 *
39 * This format also supports writing which will write packets out to the
40 * network as a form of packet replay. This should not be confused with the
41 * RT protocol which is intended to transfer captured packet records between
42 * RT-speaking programs.
43 */
44
45#include "config.h"
46#include "libtrace.h"
47#include "libtrace_int.h"
48#include "format_helper.h"
49#include "libtrace_arphrd.h"
50#include <stdlib.h>
51#include <errno.h>
52#include <unistd.h>
53#include <string.h>
54#include <assert.h>
55
56#ifdef HAVE_INTTYPES_H
57#  include <inttypes.h>
58#else
59# error "Can't find inttypes.h"
60#endif
61
62#include "format_linux_common.h"
63
64
65#ifdef HAVE_NETPACKET_PACKET_H
66
67
68static int linuxnative_start_input(libtrace_t *libtrace)
69{
70        int ret = linuxcommon_start_input_stream(libtrace, FORMAT_DATA_FIRST);
71        if (ret != 0) {
72                libtrace_list_deinit(FORMAT_DATA->per_stream);
73                free(libtrace->format_data);
74                libtrace->format_data = NULL;
75        }
76        return ret;
77}
78
79static int linuxnative_pstart_input(libtrace_t *libtrace) {
80        return linuxcommon_pstart_input(libtrace, linuxcommon_start_input_stream);
81}
82
83static int linuxnative_start_output(libtrace_out_t *libtrace)
84{
85        FORMAT_DATA_OUT->fd = socket(PF_PACKET, SOCK_RAW, 0);
86        if (FORMAT_DATA_OUT->fd==-1) {
87                free(FORMAT_DATA_OUT);
88                trace_set_err_out(libtrace, errno, "Failed to create raw socket");
89                return -1;
90        }
91
92        return 0;
93}
94
95static int linuxnative_fin_output(libtrace_out_t *libtrace)
96{
97        close(FORMAT_DATA_OUT->fd);
98        FORMAT_DATA_OUT->fd=-1;
99        free(libtrace->format_data);
100        return 0;
101}
102#endif /* HAVE_NETPACKET_PACKET_H */
103
104static int linuxnative_prepare_packet(libtrace_t *libtrace UNUSED, 
105                libtrace_packet_t *packet, void *buffer, 
106                libtrace_rt_types_t rt_type, uint32_t flags) {
107
108        if (packet->buffer != buffer &&
109            packet->buf_control == TRACE_CTRL_PACKET) {
110                free(packet->buffer);
111        }
112
113        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
114                packet->buf_control = TRACE_CTRL_PACKET;
115        } else
116                packet->buf_control = TRACE_CTRL_EXTERNAL;
117
118
119        packet->buffer = buffer;
120        packet->header = buffer;
121        packet->payload = (char *)buffer + 
122                sizeof(struct libtrace_linuxnative_header);
123        packet->type = rt_type;
124
125        /*
126        if (libtrace->format_data == NULL) {
127                if (linuxnative_init_input(libtrace))
128                        return -1;
129        }
130        */
131        return 0;
132       
133}
134
135
136#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
137
138/* 20 isn't enough on x86_64 */
139#define CMSG_BUF_SIZE 128
140
141#ifdef HAVE_NETPACKET_PACKET_H
142inline static int linuxnative_read_stream(libtrace_t *libtrace,
143                                          libtrace_packet_t *packet,
144                                          struct linux_per_stream_t *stream,
145                                          libtrace_message_queue_t *queue)
146{
147        struct libtrace_linuxnative_header *hdr;
148        struct msghdr msghdr;
149        struct iovec iovec;
150        unsigned char controlbuf[CMSG_BUF_SIZE];
151        struct cmsghdr *cmsg;
152        int snaplen;
153
154        uint32_t flags = 0;
155        fd_set readfds;
156        struct timeval tout;
157        int ret;
158       
159        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
160                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
161                if (!packet->buffer) {
162                        perror("Cannot allocate buffer");
163                }
164        }
165
166        flags |= TRACE_PREP_OWN_BUFFER;
167       
168        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
169
170        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
171        snaplen=LIBTRACE_MIN(
172                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
173                        (int)FORMAT_DATA->snaplen);
174        /* Prepare the msghdr and iovec for the kernel to write the
175         * captured packet into. The msghdr will point to the part of our
176         * buffer reserved for sll header, while the iovec will point at
177         * the buffer following the sll header. */
178
179        msghdr.msg_name = &hdr->hdr;
180        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
181
182        msghdr.msg_iov = &iovec;
183        msghdr.msg_iovlen = 1;
184
185        msghdr.msg_control = &controlbuf;
186        msghdr.msg_controllen = CMSG_BUF_SIZE;
187        msghdr.msg_flags = 0;
188
189        iovec.iov_base = (void*)(packet->buffer+sizeof(*hdr));
190        iovec.iov_len = snaplen;
191
192        // Check for a packet - TODO only Linux has MSG_DONTWAIT should use fctl O_NONBLOCK
193        /* Try check ahead this should be fast if something is waiting  */
194        hdr->wirelen = recvmsg(stream->fd, &msghdr, MSG_DONTWAIT | MSG_TRUNC);
195
196        /* No data was waiting */
197        if ((int) hdr->wirelen == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
198                /* Do message queue check or select */
199                int message_fd;
200                int largestfd = stream->fd;
201
202                /* Also check the message queue */
203                if (queue) {
204                        message_fd = libtrace_message_queue_get_fd(queue);
205                        if (message_fd > largestfd)
206                                largestfd = message_fd;
207                }
208                do {
209                        /* Use select to allow us to time out occasionally to check if someone
210                         * has hit Ctrl-C or otherwise wants us to stop reading and return
211                         * so they can exit their program.
212                         */
213                        tout.tv_sec = 0;
214                        tout.tv_usec = 500000;
215                        /* Make sure we reset these each loop */
216                        FD_ZERO(&readfds);
217                        FD_SET(stream->fd, &readfds);
218                        if (queue)
219                                FD_SET(message_fd, &readfds);
220
221                        ret = select(largestfd+1, &readfds, NULL, NULL, &tout);
222                        if (ret >= 1) {
223                                /* A file descriptor triggered */
224                                break;
225                        } else if (ret < 0 && errno != EINTR) {
226                                trace_set_err(libtrace, errno, "select");
227                                return -1;
228                        } else {
229                                if (libtrace_halt)
230                                        return READ_EOF;
231                        }
232                }
233                while (ret <= 0);
234
235                /* Message waiting? */
236                if (queue && FD_ISSET(message_fd, &readfds))
237                        return READ_MESSAGE;
238
239                /* We must have a packet */
240                hdr->wirelen = recvmsg(stream->fd, &msghdr, MSG_TRUNC);
241        }
242
243        if (hdr->wirelen==~0U) {
244                trace_set_err(libtrace,errno,"recvmsg");
245                return -1;
246        }
247
248        hdr->caplen=LIBTRACE_MIN((unsigned int)snaplen,(unsigned int)hdr->wirelen);
249
250        /* Extract the timestamps from the msghdr and store them in our
251         * linux native encapsulation, so that we can preserve the formatting
252         * across multiple architectures */
253
254        for (cmsg = CMSG_FIRSTHDR(&msghdr);
255                        cmsg != NULL;
256                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
257                if (cmsg->cmsg_level == SOL_SOCKET
258                        && cmsg->cmsg_type == SO_TIMESTAMP
259                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
260                       
261                        struct timeval *tv;
262                        tv = (struct timeval *)CMSG_DATA(cmsg);
263                       
264                       
265                        hdr->tv.tv_sec = tv->tv_sec;
266                        hdr->tv.tv_usec = tv->tv_usec;
267                        hdr->timestamptype = TS_TIMEVAL;
268                        break;
269                } 
270#ifdef SO_TIMESTAMPNS
271                else if (cmsg->cmsg_level == SOL_SOCKET
272                        && cmsg->cmsg_type == SO_TIMESTAMPNS
273                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timespec))) {
274
275                        struct timespec *tv;
276                        tv = (struct timespec *)CMSG_DATA(cmsg);
277
278                        hdr->ts.tv_sec = tv->tv_sec;
279                        hdr->ts.tv_nsec = tv->tv_nsec;
280                        hdr->timestamptype = TS_TIMESPEC;
281                        break;
282                }
283#endif
284        }
285
286        /* Did we not get given a timestamp? Try to get one from the
287         * file descriptor directly */
288        if (cmsg == NULL) {
289                struct timeval tv;
290                if (ioctl(stream->fd, SIOCGSTAMP,&tv)==0) {
291                        hdr->tv.tv_sec = tv.tv_sec;
292                        hdr->tv.tv_usec = tv.tv_usec;
293                        hdr->timestamptype = TS_TIMEVAL;
294                }
295                else {
296                        hdr->timestamptype = TS_NONE;
297                }
298        }
299
300        /* Buffer contains all of our packet (including our custom header) so
301         * we just need to get prepare_packet to set all our packet pointers
302         * appropriately */
303       
304        if (linuxnative_prepare_packet(libtrace, packet, packet->buffer,
305                                packet->type, flags))
306                return -1;
307       
308        return hdr->wirelen+sizeof(*hdr);
309}
310
311static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
312{
313        return linuxnative_read_stream(libtrace, packet, FORMAT_DATA_FIRST, NULL);
314}
315
316static int linuxnative_pread_packets(libtrace_t *libtrace,
317                                     libtrace_thread_t *t,
318                                     libtrace_packet_t *packets[],
319                                     UNUSED size_t nb_packets) {
320        /* For now just read one packet */
321        packets[0]->error = linuxnative_read_stream(libtrace, packets[0],
322                                                       t->format_data, &t->messages);
323        if (packets[0]->error >= 1)
324                return 1;
325        else
326                return packets[0]->error;
327}
328
329static int linuxnative_write_packet(libtrace_out_t *libtrace,
330                libtrace_packet_t *packet) 
331{
332        struct sockaddr_ll hdr;
333        int ret = 0;
334
335        if (trace_get_link_type(packet) == TRACE_TYPE_NONDATA)
336                return 0;
337
338        hdr.sll_family = AF_PACKET;
339        hdr.sll_protocol = 0;
340        hdr.sll_ifindex = if_nametoindex(libtrace->uridata);
341        hdr.sll_hatype = 0;
342        hdr.sll_pkttype = 0;
343        hdr.sll_halen = htons(6); /* FIXME */
344        memcpy(hdr.sll_addr,packet->payload,(size_t)ntohs(hdr.sll_halen));
345
346        /* This is pretty easy, just send the payload using sendto() (after
347         * setting up the sll header properly, of course) */
348        ret = sendto(FORMAT_DATA_OUT->fd,
349                        packet->payload,
350                        trace_get_capture_length(packet),
351                        0,
352                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
353
354        if (ret < 0) {
355                trace_set_err_out(libtrace, errno, "sendto failed");
356        }
357
358        return ret;
359}
360#endif /* HAVE_NETPACKET_PACKET_H */
361
362
363static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
364        uint16_t linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
365                                ->hdr.sll_hatype);
366        return linuxcommon_get_link_type(linktype);
367}
368
369static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
370        return linuxcommon_get_direction(((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype);
371}
372
373static libtrace_direction_t linuxnative_set_direction(
374                libtrace_packet_t *packet,
375                libtrace_direction_t direction) {
376        return linuxcommon_set_direction(&((struct libtrace_linuxnative_header*)(packet->buffer))->hdr, direction);
377}
378
379static struct timespec linuxnative_get_timespec(const libtrace_packet_t *packet) 
380{
381        struct libtrace_linuxnative_header *hdr = 
382                (struct libtrace_linuxnative_header*) packet->buffer;
383        /* We have to upconvert from timeval to timespec */
384        if (hdr->timestamptype == TS_TIMEVAL) {
385                struct timespec ts;
386                ts.tv_sec = hdr->tv.tv_sec;
387                ts.tv_nsec = hdr->tv.tv_usec*1000;
388                return ts;
389        }
390        else {
391                struct timespec ts;
392                ts.tv_sec = hdr->ts.tv_sec;
393                ts.tv_nsec = hdr->ts.tv_nsec;
394                return ts;
395        }
396}
397
398static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
399{
400        struct libtrace_linuxnative_header *hdr = 
401                (struct libtrace_linuxnative_header*) packet->buffer;
402        /* We have to downconvert from timespec to timeval */
403        if (hdr->timestamptype == TS_TIMESPEC) {
404                struct timeval tv;
405                tv.tv_sec = hdr->ts.tv_sec;
406                tv.tv_usec = hdr->ts.tv_nsec/1000;
407                return tv;
408        }
409        else {
410                struct timeval tv;
411                tv.tv_sec = hdr->tv.tv_sec;
412                tv.tv_usec = hdr->tv.tv_usec;
413                return tv;
414        }
415}
416
417static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
418{
419        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
420}
421
422
423static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
424{
425
426        int wirelen = ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
427
428        /* Include the missing FCS */
429        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
430                wirelen += 4;
431
432        return wirelen;
433}
434
435
436static int linuxnative_get_framing_length(UNUSED
437                const libtrace_packet_t *packet) 
438{
439        return sizeof(struct libtrace_linuxnative_header);
440}
441
442static size_t linuxnative_set_capture_length(libtrace_packet_t *packet, 
443                size_t size) {
444
445        struct libtrace_linuxnative_header *linux_hdr = NULL;
446        assert(packet);
447        if (size > trace_get_capture_length(packet)) {
448                /* We should avoid making a packet larger */
449                return trace_get_capture_length(packet);
450        }
451       
452        /* Reset the cached capture length */
453        packet->capture_length = -1;
454
455        linux_hdr = (struct libtrace_linuxnative_header *)packet->header;
456        linux_hdr->caplen = size;
457        return trace_get_capture_length(packet);
458}
459
460
461
462
463
464#ifdef HAVE_NETPACKET_PACKET_H
465static void linuxnative_help(void) {
466        printf("linuxnative format module: $Revision: 1793 $\n");
467        printf("Supported input URIs:\n");
468        printf("\tint:eth0\n");
469        printf("\n");
470        printf("Supported output URIs:\n");
471        printf("\tint:eth0\n");
472        printf("\n");
473        return;
474}
475
476static struct libtrace_format_t linuxnative = {
477        "int",
478        "$Id$",
479        TRACE_FORMAT_LINUX_NATIVE,
480        linuxcommon_probe_filename,     /* probe filename */
481        NULL,                           /* probe magic */
482        linuxcommon_init_input,         /* init_input */
483        linuxcommon_config_input,       /* config_input */
484        linuxnative_start_input,        /* start_input */
485        linuxcommon_pause_input,        /* pause_input */
486        linuxcommon_init_output,        /* init_output */
487        NULL,                           /* config_output */
488        linuxnative_start_output,       /* start_ouput */
489        linuxcommon_fin_input,          /* fin_input */
490        linuxnative_fin_output,         /* fin_output */
491        linuxnative_read_packet,        /* read_packet */
492        linuxnative_prepare_packet,     /* prepare_packet */
493        NULL,                           /* fin_packet */
494        linuxnative_write_packet,       /* write_packet */
495        linuxnative_get_link_type,      /* get_link_type */
496        linuxnative_get_direction,      /* get_direction */
497        linuxnative_set_direction,      /* set_direction */
498        NULL,                           /* get_erf_timestamp */
499        linuxnative_get_timeval,        /* get_timeval */
500        linuxnative_get_timespec,       /* get_timespec */
501        NULL,                           /* get_seconds */
502        NULL,                           /* seek_erf */
503        NULL,                           /* seek_timeval */
504        NULL,                           /* seek_seconds */
505        linuxnative_get_capture_length, /* get_capture_length */
506        linuxnative_get_wire_length,    /* get_wire_length */
507        linuxnative_get_framing_length, /* get_framing_length */
508        linuxnative_set_capture_length, /* set_capture_length */
509        NULL,                           /* get_received_packets */
510        linuxcommon_get_filtered_packets,/* get_filtered_packets */
511        linuxcommon_get_dropped_packets,/* get_dropped_packets */
512        linuxcommon_get_captured_packets,/* get_captured_packets */
513        linuxcommon_get_fd,             /* get_fd */
514        trace_event_device,             /* trace_event */
515        linuxnative_help,               /* help */
516        NULL,                                   /* next pointer */
517        {true, -1},              /* Live, no thread limit */
518        linuxnative_pstart_input,                       /* pstart_input */
519        linuxnative_pread_packets,                      /* pread_packets */
520        linuxcommon_pause_input,                        /* ppause */
521        linuxcommon_fin_input,                          /* p_fin */
522        linuxcommon_pconfig_input,                      /* pconfig input */
523        linuxcommon_pregister_thread,
524        NULL
525};
526#else
527static void linuxnative_help(void) {
528        printf("linuxnative format module: $Revision: 1793 $\n");
529        printf("Not supported on this host\n");
530}
531
532static struct libtrace_format_t linuxnative = {
533        "int",
534        "$Id$",
535        TRACE_FORMAT_LINUX_NATIVE,
536        NULL,                           /* probe filename */
537        NULL,                           /* probe magic */
538        NULL,                           /* init_input */
539        NULL,                           /* config_input */
540        NULL,                           /* start_input */
541        NULL,                           /* pause_input */
542        NULL,                           /* init_output */
543        NULL,                           /* config_output */
544        NULL,                           /* start_ouput */
545        NULL,                           /* fin_input */
546        NULL,                           /* fin_output */
547        NULL,                           /* read_packet */
548        linuxnative_prepare_packet,     /* prepare_packet */
549        NULL,                           /* fin_packet */
550        NULL,                           /* write_packet */
551        linuxnative_get_link_type,      /* get_link_type */
552        linuxnative_get_direction,      /* get_direction */
553        linuxnative_set_direction,      /* set_direction */
554        NULL,                           /* get_erf_timestamp */
555        linuxnative_get_timeval,        /* get_timeval */
556        linuxnative_get_timespec,       /* get_timespec */
557        NULL,                           /* get_seconds */
558        NULL,                           /* seek_erf */
559        NULL,                           /* seek_timeval */
560        NULL,                           /* seek_seconds */
561        linuxnative_get_capture_length, /* get_capture_length */
562        linuxnative_get_wire_length,    /* get_wire_length */
563        linuxnative_get_framing_length, /* get_framing_length */
564        linuxnative_set_capture_length, /* set_capture_length */
565        NULL,                           /* get_received_packets */
566        linuxnative_get_filtered_packets,/* get_filtered_packets */
567        linuxnative_get_dropped_packets,/* get_dropped_packets */
568        linuxnative_get_captured_packets,/* get_captured_packets */
569        linuxnative_get_fd,             /* get_fd */
570        trace_event_device,             /* trace_event */
571        linuxnative_help,               /* help */
572        NULL,                   /* next pointer */
573        NON_PARALLEL(true)
574};
575#endif /* HAVE_NETPACKET_PACKET_H */
576
577void linuxnative_constructor(void) {
578        register_format(&linuxnative);
579}
Note: See TracBrowser for help on using the repository browser.