source: lib/format_linux_common.c @ f9df20e

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since f9df20e was f9df20e, checked in by Shane Alcock <salcock@…>, 3 years ago

Fix bug where two ring: trace inputs had same fanout group.

We use rand() to assign the fanout group when we create the
input, but the rand() seed state is usually equal in both threads
at the point where we call rand().

So we end up with two inputs trying to be assigned to the same
fanout group, which fails and the second input will immediately
halt.

Also added code to try incrementing the fanout group number if
we end up clashing with another existing group. This will also
resolve any issues with the RNG producing one-off clashes.

  • Property mode set to 100644
File size: 18.7 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 file contains the common functions used by both the ring and int
28 * formats.
29 *
30 * Typically these deal with the socket descriptor or common conversions.
31 */
32
33#include "config.h"
34#include "libtrace.h"
35#include "libtrace_int.h"
36#include "format_helper.h"
37#include "libtrace_arphrd.h"
38#include <stdlib.h>
39#include <errno.h>
40#include <unistd.h>
41#include <string.h>
42#include <assert.h>
43
44#ifdef HAVE_INTTYPES_H
45#  include <inttypes.h>
46#else
47# error "Can't find inttypes.h"
48#endif
49
50#include "format_linux_common.h"
51
52unsigned int rand_seedp = 0;
53
54#ifdef HAVE_NETPACKET_PACKET_H
55
56int linuxcommon_probe_filename(const char *filename)
57{
58        /* Is this an interface? */
59        return (if_nametoindex(filename) != 0);
60}
61
62/* Compiles a libtrace BPF filter for use with a linux native socket */
63static int linuxnative_configure_bpf(libtrace_t *libtrace,
64                libtrace_filter_t *filter) {
65#if defined(HAVE_LIBPCAP) && defined(HAVE_BPF)
66        struct ifreq ifr;
67        unsigned int arphrd;
68        libtrace_dlt_t dlt;
69        libtrace_filter_t *f;
70        int sock;
71        pcap_t *pcap;
72
73        /* Take a copy of the filter object as it was passed in */
74        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
75        memcpy(f, filter, sizeof(libtrace_filter_t));
76
77        /* If we are passed a filter with "flag" set to zero, then we must
78         * compile the filterstring before continuing. This involves
79         * determining the linktype, passing the filterstring to libpcap to
80         * compile, and saving the result for trace_start() to push into the
81         * kernel.
82         * If flag is set to one, then the filter was probably generated using
83         * trace_create_filter_from_bytecode() and so we don't need to do
84         * anything (we've just copied it above).
85         */
86        if (f->flag == 0) {
87                sock = socket(PF_INET, SOCK_STREAM, 0);
88                memset(&ifr, 0, sizeof(struct ifreq));
89                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
90                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
91                        perror("Can't get HWADDR for interface");
92                        return -1;
93                }
94                close(sock);
95
96                arphrd = ifr.ifr_hwaddr.sa_family;
97                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
98
99                pcap = pcap_open_dead(dlt,
100                                FORMAT_DATA->snaplen);
101
102                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
103                        /* Filter didn't compile, set flag to 0 so we can
104                         * detect this when trace_start() is called and
105                         * produce a useful error
106                         */
107                        f->flag = 0;
108                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
109                                      "Failed to compile BPF filter (%s): %s",
110                                      f->filterstring, pcap_geterr(pcap));
111                } else {
112                        /* Set the "flag" to indicate that the filterstring
113                         * has been compiled
114                         */
115                        f->flag = 1;
116                }
117
118                pcap_close(pcap);
119
120        }
121
122        if (FORMAT_DATA->filter != NULL)
123                free(FORMAT_DATA->filter);
124
125        FORMAT_DATA->filter = f;
126
127        return 0;
128#else
129        return -1;
130#endif
131}
132
133int linuxcommon_config_input(libtrace_t *libtrace,
134                trace_option_t option,
135                void *data)
136{
137        switch(option) {
138                case TRACE_OPTION_SNAPLEN:
139                        FORMAT_DATA->snaplen=*(int*)data;
140                        return 0;
141                case TRACE_OPTION_PROMISC:
142                        FORMAT_DATA->promisc=*(int*)data;
143                        return 0;
144                case TRACE_OPTION_FILTER:
145                        return linuxnative_configure_bpf(libtrace,
146                                        (libtrace_filter_t *) data);
147                case TRACE_OPTION_HASHER:
148                        switch (*((enum hasher_types *)data)) {
149                                case HASHER_BALANCE:
150                                        // Do fanout
151                                        FORMAT_DATA->fanout_flags = PACKET_FANOUT_LB;
152                                        // Or we could balance to the CPU
153                                        return 0;
154                                case HASHER_BIDIRECTIONAL:
155                                case HASHER_UNIDIRECTIONAL:
156                                        FORMAT_DATA->fanout_flags = PACKET_FANOUT_HASH;
157                                        return 0;
158                                case HASHER_CUSTOM:
159                                        return -1;
160                        }
161                        break;
162                case TRACE_OPTION_META_FREQ:
163                        /* No meta-data for this format */
164                        break;
165                case TRACE_OPTION_EVENT_REALTIME:
166                        /* Live captures are always going to be in trace time */
167                        break;
168                case TRACE_OPTION_REPLAY_SPEEDUP:
169                        break;
170                /* Avoid default: so that future options will cause a warning
171                 * here to remind us to implement it, or flag it as
172                 * unimplementable
173                 */
174        }
175
176        /* Don't set an error - trace_config will try to deal with the
177         * option and will set an error if it fails */
178        return -1;
179}
180
181int linuxcommon_init_input(libtrace_t *libtrace)
182{
183        struct linux_per_stream_t stream_data = ZERO_LINUX_STREAM;
184
185        libtrace->format_data = (struct linux_format_data_t *)
186                malloc(sizeof(struct linux_format_data_t));
187        assert(libtrace->format_data != NULL);
188
189        FORMAT_DATA->per_stream =
190                libtrace_list_init(sizeof(stream_data));
191        assert(FORMAT_DATA->per_stream != NULL);
192
193        libtrace_list_push_back(FORMAT_DATA->per_stream, &stream_data);
194
195        FORMAT_DATA->promisc = -1;
196        FORMAT_DATA->snaplen = LIBTRACE_PACKET_BUFSIZE;
197        FORMAT_DATA->filter = NULL;
198        FORMAT_DATA->stats_valid = 0;
199        FORMAT_DATA->stats.tp_drops = 0;
200        FORMAT_DATA->stats.tp_packets = 0;
201        FORMAT_DATA->max_order = MAX_ORDER;
202        FORMAT_DATA->fanout_flags = PACKET_FANOUT_LB;
203        /* Some examples use pid for the group however that would limit a single
204         * application to use only int/ring format, instead using rand */
205        FORMAT_DATA->fanout_group = (uint16_t) (rand_r(&rand_seedp) % 65536);
206        return 0;
207}
208
209int linuxcommon_init_output(libtrace_out_t *libtrace)
210{
211        libtrace->format_data = (struct linux_format_data_out_t*)
212                malloc(sizeof(struct linux_format_data_out_t));
213        assert(libtrace->format_data != NULL);
214
215        FORMAT_DATA_OUT->fd = -1;
216        FORMAT_DATA_OUT->tx_ring = NULL;
217        FORMAT_DATA_OUT->txring_offset = 0;
218        FORMAT_DATA_OUT->queue = 0;
219        FORMAT_DATA_OUT->max_order = MAX_ORDER;
220        return 0;
221}
222
223/* Close an input stream, this is safe to be called part way through
224 * initilisation as a cleanup function assuming streams were set to
225 * ZERO_LINUX_STREAM to begin with.
226 *
227 * This works correctly with both int and ring
228 */
229void linuxcommon_close_input_stream(libtrace_t *libtrace,
230                                    struct linux_per_stream_t *stream) {
231        if (stream->fd != -1)
232                close(stream->fd);
233        stream->fd = -1;
234        if (stream->rx_ring != MAP_FAILED)
235                munmap(stream->rx_ring,
236                       stream->req.tp_block_size *
237                       stream->req.tp_block_nr);
238        stream->rx_ring = MAP_FAILED;
239        stream->rxring_offset = 0;
240        FORMAT_DATA->dev_stats.if_name[0] = 0;
241}
242
243#define REPEAT_16(x) x x x x x x x x x x x x x x x x
244#define xstr(s) str(s)
245#define str(s) #s
246
247/* These don't typically reset however an interface does exist to reset them */
248static int linuxcommon_get_dev_statistics(libtrace_t *libtrace, struct linux_dev_stats *stats) {
249        FILE *file;
250        char line[1024];
251        struct linux_dev_stats tmp_stats;
252
253        file = fopen("/proc/net/dev","r");
254        if (file == NULL) {
255                return -1;
256        }
257
258        /* Skip 2 header lines */
259        if (fgets(line, sizeof(line), file) == NULL) {
260                fclose(file);
261                return -1;
262        }
263
264        if (fgets(line, sizeof(line), file) == NULL) {
265                fclose(file);
266                return -1;
267        }
268
269        while (!(feof(file)||ferror(file))) {
270                int tot;
271                if (fgets(line, sizeof(line), file) == NULL)
272                        break;
273
274                tot = sscanf(line, " %"xstr(IF_NAMESIZE)"[^:]:" REPEAT_16(" %"SCNd64),
275                             tmp_stats.if_name,
276                             &tmp_stats.rx_bytes,
277                             &tmp_stats.rx_packets,
278                             &tmp_stats.rx_errors,
279                             &tmp_stats.rx_drops,
280                             &tmp_stats.rx_fifo,
281                             &tmp_stats.rx_frame,
282                             &tmp_stats.rx_compressed,
283                             &tmp_stats.rx_multicast,
284                             &tmp_stats.tx_bytes,
285                             &tmp_stats.tx_packets,
286                             &tmp_stats.tx_errors,
287                             &tmp_stats.tx_drops,
288                             &tmp_stats.tx_fifo,
289                             &tmp_stats.tx_colls,
290                             &tmp_stats.tx_carrier,
291                             &tmp_stats.tx_compressed);
292                if (tot != 17)
293                        continue;
294                if (strncmp(tmp_stats.if_name, libtrace->uridata, IF_NAMESIZE) == 0) {
295                        *stats = tmp_stats;
296                        fclose(file);
297                        return 0;
298                }
299        }
300        fclose(file);
301        return -1;
302}
303
304/* Start an input stream
305 * - Opens the file descriptor
306 * - Sets promiscuous correctly
307 * - Sets socket option
308 * - Add BPF filter
309 *
310 * The output is ready for int directly, for ring the conversion to ring still
311 * needs to take place.
312 */
313int linuxcommon_start_input_stream(libtrace_t *libtrace,
314                                   struct linux_per_stream_t *stream)
315{
316        struct sockaddr_ll addr;
317        const int one = 1;
318        memset(&addr,0,sizeof(addr));
319        libtrace_filter_t *filter = FORMAT_DATA->filter;
320
321        stream->last_timestamp = 0;
322
323        /* Create a raw socket for reading packets on */
324        stream->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
325        if (stream->fd==-1) {
326                trace_set_err(libtrace, errno, "Could not create raw socket");
327                return -1;
328        }
329
330        /* Bind to the capture interface */
331        addr.sll_family = AF_PACKET;
332        addr.sll_protocol = htons(ETH_P_ALL);
333        if (strlen(libtrace->uridata)) {
334                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
335                if (addr.sll_ifindex == 0) {
336                        linuxcommon_close_input_stream(libtrace, stream);
337                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
338                                      "Failed to find interface %s",
339                                      libtrace->uridata);
340                        return -1;
341                }
342        } else {
343                addr.sll_ifindex = 0;
344        }
345        if (bind(stream->fd,
346                 (struct sockaddr*)&addr,
347                 (socklen_t)sizeof(addr))==-1) {
348                linuxcommon_close_input_stream(libtrace, stream);
349                trace_set_err(libtrace, errno,
350                              "Failed to bind to interface %s",
351                              libtrace->uridata);
352                return -1;
353        }
354
355        /* If promisc hasn't been specified, set it to "true" if we're
356         * capturing on one interface, or "false" if we're capturing on
357         * all interfaces.
358         */
359        if (FORMAT_DATA->promisc==-1) {
360                if (addr.sll_ifindex!=0)
361                        FORMAT_DATA->promisc=1;
362                else
363                        FORMAT_DATA->promisc=0;
364        }
365
366        /* Enable promiscuous mode, if requested */
367        if (FORMAT_DATA->promisc) {
368                struct packet_mreq mreq;
369                socklen_t socklen = sizeof(mreq);
370                memset(&mreq,0,sizeof(mreq));
371                mreq.mr_ifindex = addr.sll_ifindex;
372                mreq.mr_type = PACKET_MR_PROMISC;
373                if (setsockopt(stream->fd,
374                               SOL_PACKET,
375                               PACKET_ADD_MEMBERSHIP,
376                               &mreq,
377                               socklen)==-1) {
378                        perror("setsockopt(PROMISC)");
379                }
380        }
381
382        /* Set the timestamp option on the socket - aim for the most detailed
383         * clock resolution possible */
384#ifdef SO_TIMESTAMPNS
385        if (setsockopt(stream->fd,
386                       SOL_SOCKET,
387                       SO_TIMESTAMPNS,
388                       &one,
389                       (socklen_t)sizeof(one))!=-1) {
390                FORMAT_DATA->timestamptype = TS_TIMESPEC;
391        }
392        else
393        /* DANGER: This is a dangling else to only do the next setsockopt()
394         * if we fail the first! */
395#endif
396                if (setsockopt(stream->fd,
397                               SOL_SOCKET,
398                               SO_TIMESTAMP,
399                               &one,
400                               (socklen_t)sizeof(one))!=-1) {
401                        FORMAT_DATA->timestamptype = TS_TIMEVAL;
402                }
403                else
404                        FORMAT_DATA->timestamptype = TS_NONE;
405
406        /* Push BPF filter into the kernel. At this stage we can safely assume
407         * that the filterstring has been compiled, or the filter was supplied
408         * pre-compiled.
409         */
410#ifdef HAVE_BPF
411        if (filter != NULL) {
412                /* Check if the filter was successfully compiled. If not,
413                 * it is probably a bad filter and we should return an error
414                 * before the caller tries to read any packets */
415                if (filter->flag == 0) {
416                        linuxcommon_close_input_stream(libtrace, stream);
417                        trace_set_err(libtrace, TRACE_ERR_BAD_FILTER,
418                                      "Cannot attach a bad filter to %s",
419                                      libtrace->uridata);
420                        return -1;
421                }
422
423                if (setsockopt(stream->fd,
424                               SOL_SOCKET,
425                               SO_ATTACH_FILTER,
426                               &filter->filter,
427                               sizeof(filter->filter)) == -1) {
428                        perror("setsockopt(SO_ATTACH_FILTER)");
429                }
430        }
431#endif
432
433        /* Consume any buffered packets that were received before the socket
434         * was properly setup, including those which missed the filter and
435         * bind()ing to an interface.
436         *
437         * If packet rate is high this could therotically hang forever. 4K
438         * should be a large enough limit.
439         */
440        int count = 0;
441        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
442        while(count < 4096 &&
443                recv(stream->fd,
444                   buf,
445                   (size_t)LIBTRACE_PACKET_BUFSIZE,
446                   MSG_DONTWAIT) != -1) { count++; }
447        free(buf);
448
449        /* Mark that the stats are valid and apply an offset */
450        FORMAT_DATA->stats_valid = 1;
451        /* Offset by number we ate for each stream and reset stats after pause */
452        FORMAT_DATA->stats.tp_packets = -count;
453        FORMAT_DATA->stats.tp_drops = 0;
454
455        if (linuxcommon_get_dev_statistics(libtrace, &FORMAT_DATA->dev_stats) != 0) {
456                /* Mark this as bad */
457                FORMAT_DATA->dev_stats.if_name[0] = 0;
458        }
459
460        return 0;
461}
462
463int linuxcommon_pause_input(libtrace_t *libtrace)
464{
465        size_t i;
466
467        /* Stop and detach each stream */
468        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
469                struct linux_per_stream_t *stream;
470                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
471                linuxcommon_close_input_stream(libtrace, stream);
472        }
473
474        return 0;
475}
476
477int linuxcommon_fin_input(libtrace_t *libtrace)
478{
479        if (libtrace->format_data) {
480                if (FORMAT_DATA->filter != NULL)
481                        free(FORMAT_DATA->filter);
482
483                if (FORMAT_DATA->per_stream)
484                        libtrace_list_deinit(FORMAT_DATA->per_stream);
485
486                free(libtrace->format_data);
487        }
488
489        return 0;
490}
491
492int linuxcommon_pregister_thread(libtrace_t *libtrace,
493                                 libtrace_thread_t *t,
494                                 bool reading) {
495        if (reading) {
496                /* XXX TODO remove this oneday make sure hasher thread still works */
497                struct linux_per_stream_t *stream;
498                stream = libtrace_list_get_index(FORMAT_DATA->per_stream,
499                                                 t->perpkt_num)->data;
500                t->format_data = stream;
501                if (!stream) {
502                        /* This should never happen and indicates an
503                         * internal libtrace bug */
504                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
505                                      "Failed to attached thread %d to a stream",
506                                      t->perpkt_num);
507                        return -1;
508                }
509        }
510        return 0;
511}
512
513/* These counters reset with each read */
514static void linuxcommon_update_socket_statistics(libtrace_t *libtrace) {
515        struct tpacket_stats stats;
516        size_t i;
517        socklen_t len = sizeof(stats);
518
519        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
520                struct linux_per_stream_t *stream;
521                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
522                if (stream->fd != -1) {
523                        if (getsockopt(stream->fd,
524                                   SOL_PACKET,
525                                   PACKET_STATISTICS,
526                                   &stats,
527                                   &len) == 0) {
528                                if (FORMAT_DATA->stats_valid==0) {
529                                        FORMAT_DATA->stats.tp_drops = stats.tp_drops;
530                                        FORMAT_DATA->stats.tp_packets = stats.tp_packets;
531                                        FORMAT_DATA->stats_valid = 1;
532                                } else {
533                                        FORMAT_DATA->stats.tp_drops += stats.tp_drops;
534                                        FORMAT_DATA->stats.tp_packets += stats.tp_packets;
535                                }
536                        } else {
537                                perror("getsockopt PACKET_STATISTICS failed");
538                        }
539                }
540        }
541}
542
543#define DEV_DIFF(x) (dev_stats.x - FORMAT_DATA->dev_stats.x)
544/* Note these statistics come from two different sources, the socket itself and
545 * the linux device. As such this means it is highly likely that their is some
546 * margin of error in the returned statistics, we perform basic sanitising so
547 * that these are not too noticable.
548 */
549void linuxcommon_get_statistics(libtrace_t *libtrace, libtrace_stat_t *stat) {
550        struct linux_dev_stats dev_stats;
551        if (libtrace->format_data == NULL)
552                return;
553        /* Do we need to consider the case after the trace is closed? */
554        if (FORMAT_DATA_FIRST->fd == -1) {
555                /* This is probably a 'dead' trace so obviously we can't query
556                 * the socket for capture counts, can we? */
557                return;
558        }
559
560        dev_stats.if_name[0] = 0; /* This will be set if we retrive valid stats */
561        /* Do we have starting stats to compare to? */
562        if (FORMAT_DATA->dev_stats.if_name[0] != 0) {
563                linuxcommon_get_dev_statistics(libtrace, &dev_stats);
564        }
565        linuxcommon_update_socket_statistics(libtrace);
566
567        /* filtered count == dev received - socket received */
568        if (FORMAT_DATA->filter != NULL &&
569            FORMAT_DATA->stats_valid &&
570            dev_stats.if_name[0]) {
571                uint64_t filtered = DEV_DIFF(rx_packets) -
572                                    FORMAT_DATA->stats.tp_packets;
573                /* Check the value is sane, due to timing it could be below 0 */
574                if (filtered < UINT64_MAX - 100000) {
575                        stat->filtered += filtered;
576                }
577        }
578
579        /* dropped count == socket dropped + dev dropped */
580        if (FORMAT_DATA->stats_valid) {
581                stat->dropped_valid = 1;
582                stat->dropped = FORMAT_DATA->stats.tp_drops;
583                if (dev_stats.if_name[0]) {
584                        stat->dropped += DEV_DIFF(rx_drops);
585                }
586        }
587
588        /* received count - All good packets even those dropped or filtered */
589        if (dev_stats.if_name[0]) {
590                stat->received_valid = 1;
591                stat->received = DEV_DIFF(rx_packets) + DEV_DIFF(rx_drops);
592        }
593
594        /* captured count - received and but not dropped */
595        if (dev_stats.if_name[0] && FORMAT_DATA->stats_valid) {
596                stat->captured_valid = 1;
597                stat->captured = DEV_DIFF(rx_packets) - FORMAT_DATA->stats.tp_drops;
598        }
599
600        /* errors */
601        if (dev_stats.if_name[0]) {
602                stat->errors_valid = 1;
603                stat->errors = DEV_DIFF(rx_errors);
604        }
605
606}
607
608int linuxcommon_get_fd(const libtrace_t *libtrace) {
609        if (libtrace->format_data == NULL)
610                return -1;
611        return FORMAT_DATA_FIRST->fd;
612}
613
614int linuxcommon_pstart_input(libtrace_t *libtrace,
615                             int (*start_stream)(libtrace_t *, struct linux_per_stream_t*)) {
616        int i = 0;
617        int tot = libtrace->perpkt_thread_count;
618        int iserror = 0;
619        struct linux_per_stream_t empty_stream = ZERO_LINUX_STREAM;
620
621        for (i = 0; i < tot; ++i)
622        {
623                struct linux_per_stream_t *stream;
624                /* Add storage for another stream */
625                if (libtrace_list_get_size(FORMAT_DATA->per_stream) <= (size_t) i)
626                        libtrace_list_push_back(FORMAT_DATA->per_stream, &empty_stream);
627
628                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
629                if (start_stream(libtrace, stream) != 0) {
630                        iserror = 1;
631                        break;
632                }
633                if (linuxcommon_to_packet_fanout(libtrace, stream) != 0)
634                {
635                        iserror = 1;
636                        close(stream->fd);
637                        stream->fd = -1;
638                        break;
639                }
640        }
641
642        if (iserror) {
643                /* Free those that succeeded */
644                for (i = i - 1; i >= 0; i--) {
645                        struct linux_per_stream_t *stream;
646                        stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
647                        linuxcommon_close_input_stream(libtrace, stream);
648                }
649                return -1;
650        }
651
652        return 0;
653}
654
655#else /* HAVE_NETPACKET_PACKET_H */
656
657/* No NETPACKET - So this format is not live */
658void linuxcommon_get_statistics(libtrace_t *libtrace UNUSED,
659                                libtrace_stat_t *stat UNUSED) {
660        return;
661}
662
663#endif /* HAVE_NETPACKET_PACKET_H */
664
Note: See TracBrowser for help on using the repository browser.