source: lib/format_linux_common.c @ ebed638

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

Don't munmap ring rx buffers until last possible moment.

As soon as we munmap the buffers, any packets contained within
those buffers become invalid -- however, the user application may
still have references to those packets and could try to operate
on them without knowing that the memory holding the packet payload
is invalid.

Previously, the buffers were munmapped when the trace was paused,
which was causing crashes and invalid memory accesses.

Instead, we now only munmap the buffer if either the trace is
restarted or destroyed, so the packets will remain valid for
longer. Also, the new "start" iteration counting added in an
earlier commit means we can now recognise when a packet belongs
to an unmapped buffer and therefore return appropriate errors if
a user tries to interact with the packet.

This also fixes the assertion failure when freeing a ring packet
after the ring trace has been paused, i.e. after a call to
trace_pstop().

  • Property mode set to 100644
File size: 19.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 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 - 1);
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        FORMAT_DATA->dev_stats.if_name[0] = 0;
235
236        /* Don't munmap the rx_ring here -- keep it around as long as
237         * possible to ensure that any packets that the user is still
238         * holding references to remain valid.
239         *
240         * Don't worry, linuxring will munmap the rx_ring as soon as
241         * someone either destroys or restarts the trace. At that point,
242         * any remaining packets from the old ring will be recognisable
243         * as invalid.
244         */
245}
246
247#define REPEAT_16(x) x x x x x x x x x x x x x x x x
248#define xstr(s) str(s)
249#define str(s) #s
250
251/* These don't typically reset however an interface does exist to reset them */
252static int linuxcommon_get_dev_statistics(libtrace_t *libtrace, struct linux_dev_stats *stats) {
253        FILE *file;
254        char line[1024];
255        struct linux_dev_stats tmp_stats;
256
257        file = fopen("/proc/net/dev","r");
258        if (file == NULL) {
259                return -1;
260        }
261
262        /* Skip 2 header lines */
263        if (fgets(line, sizeof(line), file) == NULL) {
264                fclose(file);
265                return -1;
266        }
267
268        if (fgets(line, sizeof(line), file) == NULL) {
269                fclose(file);
270                return -1;
271        }
272
273        while (!(feof(file)||ferror(file))) {
274                int tot;
275                if (fgets(line, sizeof(line), file) == NULL)
276                        break;
277
278                tot = sscanf(line, " %"xstr(IF_NAMESIZE)"[^:]:" REPEAT_16(" %"SCNd64),
279                             tmp_stats.if_name,
280                             &tmp_stats.rx_bytes,
281                             &tmp_stats.rx_packets,
282                             &tmp_stats.rx_errors,
283                             &tmp_stats.rx_drops,
284                             &tmp_stats.rx_fifo,
285                             &tmp_stats.rx_frame,
286                             &tmp_stats.rx_compressed,
287                             &tmp_stats.rx_multicast,
288                             &tmp_stats.tx_bytes,
289                             &tmp_stats.tx_packets,
290                             &tmp_stats.tx_errors,
291                             &tmp_stats.tx_drops,
292                             &tmp_stats.tx_fifo,
293                             &tmp_stats.tx_colls,
294                             &tmp_stats.tx_carrier,
295                             &tmp_stats.tx_compressed);
296                if (tot != 17)
297                        continue;
298                if (strncmp(tmp_stats.if_name, libtrace->uridata, IF_NAMESIZE) == 0) {
299                        *stats = tmp_stats;
300                        fclose(file);
301                        return 0;
302                }
303        }
304        fclose(file);
305        return -1;
306}
307
308/* Start an input stream
309 * - Opens the file descriptor
310 * - Sets promiscuous correctly
311 * - Sets socket option
312 * - Add BPF filter
313 *
314 * The output is ready for int directly, for ring the conversion to ring still
315 * needs to take place.
316 */
317int linuxcommon_start_input_stream(libtrace_t *libtrace,
318                                   struct linux_per_stream_t *stream)
319{
320        struct sockaddr_ll addr;
321        const int one = 1;
322        memset(&addr,0,sizeof(addr));
323        libtrace_filter_t *filter = FORMAT_DATA->filter;
324
325        stream->last_timestamp = 0;
326
327        /* Create a raw socket for reading packets on */
328        stream->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
329        if (stream->fd==-1) {
330                trace_set_err(libtrace, errno, "Could not create raw socket");
331                return -1;
332        }
333
334        /* Bind to the capture interface */
335        addr.sll_family = AF_PACKET;
336        addr.sll_protocol = htons(ETH_P_ALL);
337        if (strlen(libtrace->uridata)) {
338                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
339                if (addr.sll_ifindex == 0) {
340                        linuxcommon_close_input_stream(libtrace, stream);
341                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
342                                      "Failed to find interface %s",
343                                      libtrace->uridata);
344                        return -1;
345                }
346        } else {
347                addr.sll_ifindex = 0;
348        }
349        if (bind(stream->fd,
350                 (struct sockaddr*)&addr,
351                 (socklen_t)sizeof(addr))==-1) {
352                linuxcommon_close_input_stream(libtrace, stream);
353                trace_set_err(libtrace, errno,
354                              "Failed to bind to interface %s",
355                              libtrace->uridata);
356                return -1;
357        }
358
359        /* If promisc hasn't been specified, set it to "true" if we're
360         * capturing on one interface, or "false" if we're capturing on
361         * all interfaces.
362         */
363        if (FORMAT_DATA->promisc==-1) {
364                if (addr.sll_ifindex!=0)
365                        FORMAT_DATA->promisc=1;
366                else
367                        FORMAT_DATA->promisc=0;
368        }
369
370        /* Enable promiscuous mode, if requested */
371        if (FORMAT_DATA->promisc) {
372                struct packet_mreq mreq;
373                socklen_t socklen = sizeof(mreq);
374                memset(&mreq,0,sizeof(mreq));
375                mreq.mr_ifindex = addr.sll_ifindex;
376                mreq.mr_type = PACKET_MR_PROMISC;
377                if (setsockopt(stream->fd,
378                               SOL_PACKET,
379                               PACKET_ADD_MEMBERSHIP,
380                               &mreq,
381                               socklen)==-1) {
382                        perror("setsockopt(PROMISC)");
383                }
384        }
385
386        /* Set the timestamp option on the socket - aim for the most detailed
387         * clock resolution possible */
388#ifdef SO_TIMESTAMPNS
389        if (setsockopt(stream->fd,
390                       SOL_SOCKET,
391                       SO_TIMESTAMPNS,
392                       &one,
393                       (socklen_t)sizeof(one))!=-1) {
394                FORMAT_DATA->timestamptype = TS_TIMESPEC;
395        }
396        else
397        /* DANGER: This is a dangling else to only do the next setsockopt()
398         * if we fail the first! */
399#endif
400                if (setsockopt(stream->fd,
401                               SOL_SOCKET,
402                               SO_TIMESTAMP,
403                               &one,
404                               (socklen_t)sizeof(one))!=-1) {
405                        FORMAT_DATA->timestamptype = TS_TIMEVAL;
406                }
407                else
408                        FORMAT_DATA->timestamptype = TS_NONE;
409
410        /* Push BPF filter into the kernel. At this stage we can safely assume
411         * that the filterstring has been compiled, or the filter was supplied
412         * pre-compiled.
413         */
414#ifdef HAVE_BPF
415        if (filter != NULL) {
416                /* Check if the filter was successfully compiled. If not,
417                 * it is probably a bad filter and we should return an error
418                 * before the caller tries to read any packets */
419                if (filter->flag == 0) {
420                        linuxcommon_close_input_stream(libtrace, stream);
421                        trace_set_err(libtrace, TRACE_ERR_BAD_FILTER,
422                                      "Cannot attach a bad filter to %s",
423                                      libtrace->uridata);
424                        return -1;
425                }
426
427                if (setsockopt(stream->fd,
428                               SOL_SOCKET,
429                               SO_ATTACH_FILTER,
430                               &filter->filter,
431                               sizeof(filter->filter)) == -1) {
432                        perror("setsockopt(SO_ATTACH_FILTER)");
433                }
434        }
435#endif
436
437        /* Consume any buffered packets that were received before the socket
438         * was properly setup, including those which missed the filter and
439         * bind()ing to an interface.
440         *
441         * If packet rate is high this could therotically hang forever. 4K
442         * should be a large enough limit.
443         */
444        int count = 0;
445        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
446        while(count < 4096 &&
447                recv(stream->fd,
448                   buf,
449                   (size_t)LIBTRACE_PACKET_BUFSIZE,
450                   MSG_DONTWAIT) != -1) { count++; }
451        free(buf);
452
453        /* Mark that the stats are valid and apply an offset */
454        FORMAT_DATA->stats_valid = 1;
455        /* Offset by number we ate for each stream and reset stats after pause */
456        FORMAT_DATA->stats.tp_packets = -count;
457        FORMAT_DATA->stats.tp_drops = 0;
458
459        if (linuxcommon_get_dev_statistics(libtrace, &FORMAT_DATA->dev_stats) != 0) {
460                /* Mark this as bad */
461                FORMAT_DATA->dev_stats.if_name[0] = 0;
462        }
463
464        return 0;
465}
466
467int linuxcommon_pause_input(libtrace_t *libtrace)
468{
469        size_t i;
470
471        /* Stop and detach each stream */
472        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
473                struct linux_per_stream_t *stream;
474                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
475                linuxcommon_close_input_stream(libtrace, stream);
476        }
477
478        return 0;
479}
480
481int linuxcommon_fin_input(libtrace_t *libtrace)
482{
483        if (libtrace->format_data) {
484                if (FORMAT_DATA->filter != NULL)
485                        free(FORMAT_DATA->filter);
486
487                if (FORMAT_DATA->per_stream)
488                        libtrace_list_deinit(FORMAT_DATA->per_stream);
489
490                free(libtrace->format_data);
491        }
492
493        return 0;
494}
495
496int linuxcommon_pregister_thread(libtrace_t *libtrace,
497                                 libtrace_thread_t *t,
498                                 bool reading) {
499        if (reading) {
500                /* XXX TODO remove this oneday make sure hasher thread still works */
501                struct linux_per_stream_t *stream;
502                stream = libtrace_list_get_index(FORMAT_DATA->per_stream,
503                                                 t->perpkt_num)->data;
504                t->format_data = stream;
505                if (!stream) {
506                        /* This should never happen and indicates an
507                         * internal libtrace bug */
508                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED,
509                                      "Failed to attached thread %d to a stream",
510                                      t->perpkt_num);
511                        return -1;
512                }
513        }
514        return 0;
515}
516
517/* These counters reset with each read */
518static void linuxcommon_update_socket_statistics(libtrace_t *libtrace) {
519        struct tpacket_stats stats;
520        size_t i;
521        socklen_t len = sizeof(stats);
522
523        for (i = 0; i < libtrace_list_get_size(FORMAT_DATA->per_stream); ++i) {
524                struct linux_per_stream_t *stream;
525                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
526                if (stream->fd != -1) {
527                        if (getsockopt(stream->fd,
528                                   SOL_PACKET,
529                                   PACKET_STATISTICS,
530                                   &stats,
531                                   &len) == 0) {
532                                if (FORMAT_DATA->stats_valid==0) {
533                                        FORMAT_DATA->stats.tp_drops = stats.tp_drops;
534                                        FORMAT_DATA->stats.tp_packets = stats.tp_packets;
535                                        FORMAT_DATA->stats_valid = 1;
536                                } else {
537                                        FORMAT_DATA->stats.tp_drops += stats.tp_drops;
538                                        FORMAT_DATA->stats.tp_packets += stats.tp_packets;
539                                }
540                        } else {
541                                perror("getsockopt PACKET_STATISTICS failed");
542                        }
543                }
544        }
545}
546
547#define DEV_DIFF(x) (dev_stats.x - FORMAT_DATA->dev_stats.x)
548/* Note these statistics come from two different sources, the socket itself and
549 * the linux device. As such this means it is highly likely that their is some
550 * margin of error in the returned statistics, we perform basic sanitising so
551 * that these are not too noticable.
552 */
553void linuxcommon_get_statistics(libtrace_t *libtrace, libtrace_stat_t *stat) {
554        struct linux_dev_stats dev_stats;
555        if (libtrace->format_data == NULL)
556                return;
557        /* Do we need to consider the case after the trace is closed? */
558        if (FORMAT_DATA_FIRST->fd == -1) {
559                /* This is probably a 'dead' trace so obviously we can't query
560                 * the socket for capture counts, can we? */
561                return;
562        }
563
564        dev_stats.if_name[0] = 0; /* This will be set if we retrive valid stats */
565        /* Do we have starting stats to compare to? */
566        if (FORMAT_DATA->dev_stats.if_name[0] != 0) {
567                linuxcommon_get_dev_statistics(libtrace, &dev_stats);
568        }
569        linuxcommon_update_socket_statistics(libtrace);
570
571        /* filtered count == dev received - socket received */
572        if (FORMAT_DATA->filter != NULL &&
573            FORMAT_DATA->stats_valid &&
574            dev_stats.if_name[0]) {
575                uint64_t filtered = DEV_DIFF(rx_packets) -
576                                    FORMAT_DATA->stats.tp_packets;
577                /* Check the value is sane, due to timing it could be below 0 */
578                if (filtered < UINT64_MAX - 100000) {
579                        stat->filtered += filtered;
580                }
581        }
582
583        /* dropped count == socket dropped + dev dropped */
584        if (FORMAT_DATA->stats_valid) {
585                stat->dropped_valid = 1;
586                stat->dropped = FORMAT_DATA->stats.tp_drops;
587                if (dev_stats.if_name[0]) {
588                        stat->dropped += DEV_DIFF(rx_drops);
589                }
590        }
591
592        /* received count - All good packets even those dropped or filtered */
593        if (dev_stats.if_name[0]) {
594                stat->received_valid = 1;
595                stat->received = DEV_DIFF(rx_packets) + DEV_DIFF(rx_drops);
596        }
597
598        /* captured count - received and but not dropped */
599        if (dev_stats.if_name[0] && FORMAT_DATA->stats_valid) {
600                stat->captured_valid = 1;
601                stat->captured = DEV_DIFF(rx_packets) - FORMAT_DATA->stats.tp_drops;
602        }
603
604        /* errors */
605        if (dev_stats.if_name[0]) {
606                stat->errors_valid = 1;
607                stat->errors = DEV_DIFF(rx_errors);
608        }
609
610}
611
612int linuxcommon_get_fd(const libtrace_t *libtrace) {
613        if (libtrace->format_data == NULL)
614                return -1;
615        return FORMAT_DATA_FIRST->fd;
616}
617
618int linuxcommon_pstart_input(libtrace_t *libtrace,
619                             int (*start_stream)(libtrace_t *, struct linux_per_stream_t*)) {
620        int i = 0;
621        int tot = libtrace->perpkt_thread_count;
622        int iserror = 0;
623        struct linux_per_stream_t empty_stream = ZERO_LINUX_STREAM;
624
625        for (i = 0; i < tot; ++i)
626        {
627                struct linux_per_stream_t *stream;
628                /* Add storage for another stream */
629                if (libtrace_list_get_size(FORMAT_DATA->per_stream) <= (size_t) i)
630                        libtrace_list_push_back(FORMAT_DATA->per_stream, &empty_stream);
631
632                stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
633                if (start_stream(libtrace, stream) != 0) {
634                        iserror = 1;
635                        break;
636                }
637                if (linuxcommon_to_packet_fanout(libtrace, stream) != 0)
638                {
639                        iserror = 1;
640                        close(stream->fd);
641                        stream->fd = -1;
642                        break;
643                }
644        }
645
646        if (iserror) {
647                /* Free those that succeeded */
648                for (i = i - 1; i >= 0; i--) {
649                        struct linux_per_stream_t *stream;
650                        stream = libtrace_list_get_index(FORMAT_DATA->per_stream, i)->data;
651                        linuxcommon_close_input_stream(libtrace, stream);
652                }
653                return -1;
654        }
655
656        return 0;
657}
658
659#else /* HAVE_NETPACKET_PACKET_H */
660
661/* No NETPACKET - So this format is not live */
662void linuxcommon_get_statistics(libtrace_t *libtrace UNUSED,
663                                libtrace_stat_t *stat UNUSED) {
664        return;
665}
666
667#endif /* HAVE_NETPACKET_PACKET_H */
668
Note: See TracBrowser for help on using the repository browser.