Changeset 4649fea


Ignore:
Timestamp:
08/07/14 15:48:18 (6 years ago)
Author:
Shane Alcock <salcock@…>
Branches:
4.0.1-hotfixes, cachetimestamps, develop, dpdk-ndag, etsilive, libtrace4, master, ndag_format, pfring, rc-4.0.1, rc-4.0.2, rc-4.0.3, rc-4.0.4, ringdecrementfix, ringperformance, ringtimestampfixes
Children:
0ae5feb
Parents:
b8d8186
Message:

Fix trace_event errors with pcapint: and filters

If a packet arrives between the time a live pcap capture
is created and the time the filter is set, the pcap fd acts
as though there is a packet available even if pcap_next_ex will
time out due to no packets matching the filter.

This can wreak havoc with trace_event, which relies on select
to know whether it will be able to call trace_read_packet
without blocking. If the filter doesn't match any packets,
trace_read_packet will block forever -- defeat the purpose of
using trace_event in the first place.

The solution is to always try to consume a packet immediately after
calling pcap_setfilter. Any "bad" packets will be removed from the
queue until a packet that matches the filter is hit or pcap_next_ex
times out. Either way, select should work properly again, at the
cost of possible one legit packet being consumed during startup.

Thanks to Mike Schiffman for reporting this bug (and the previous
one re: inconsistent behaviour when the filter is bogus).

Location:
lib
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • lib/format_helper.c

    rb8d8186 r4649fea  
    9898         * solution. */
    9999
    100         do {
     100        do {
    101101                tv.tv_sec = 0;
    102102                tv.tv_usec = 0;
  • lib/format_pcap.c

    ra6c77b0 r4649fea  
    295295        }
    296296#endif
     297#ifdef HAVE_PCAP_SETNONBLOCK
     298        pcap_setnonblock(INPUT.pcap,0,errbuf);
     299#endif
    297300        /* Set a filter if one is defined */
    298301        if (DATA(libtrace)->filter) {
    299                 if (DATA(libtrace)->filter->flag == 0) {
     302                struct pcap_pkthdr *pcap_hdr = NULL;
     303                u_char *pcap_payload = NULL;
     304                int pcapret;
     305               
     306                if (DATA(libtrace)->filter->flag == 0) {
    300307                        pcap_compile(INPUT.pcap,
    301308                                        &DATA(libtrace)->filter->filter,
     
    304311                        DATA(libtrace)->filter->flag = 1;
    305312                }
    306                 if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter)
     313                if (pcap_setfilter(INPUT.pcap,&DATA(libtrace)->filter->filter)
    307314                        == -1) {
    308315                        trace_set_err(libtrace,TRACE_ERR_INIT_FAILED,"%s",
     
    310317                        return -1; /* failure */
    311318                }
    312         }
    313 #ifdef HAVE_PCAP_SETNONBLOCK
    314         pcap_setnonblock(INPUT.pcap,0,errbuf);
    315 #endif
     319
     320                /* Consume the first packet in the queue, as this may not
     321                 * have had the filter applied to it.
     322                 *
     323                 * Otherwise we can get problems with the event API, where
     324                 * select tells us that there is a packet available but
     325                 * calling trace_read_packet will block forever because the
     326                 * packet in the queue didn't match the filter so
     327                 * pcap_next_ex returns "timed out".
     328                 *
     329                 * This does mean we may consume a legitimate packet, but
     330                 * that's a pretty small downside compared with trace_event
     331                 * getting stuck in an infinite loop because of pcap
     332                 * wackiness.
     333                 *
     334                 * For some reason, we only need to consume one packet for
     335                 * this to work, so let's hope that holds in the future.
     336                 */
     337                do {
     338                        pcapret = pcap_next_ex(INPUT.pcap, &pcap_hdr,
     339                                (const u_char **)&pcap_payload);
     340                } while (0);
     341
     342                if (pcapret < 0)
     343                        return -1;
     344        }
    316345        return 0; /* success */
    317346}
     
    421450                                if (libtrace_halt)
    422451                                        return 0;
    423                                 continue; /* timeout expired */
     452                                continue; /* timeout expired */
    424453                        case -1:
    425454                                trace_set_err(libtrace,TRACE_ERR_BAD_PACKET,
Note: See TracChangeset for help on using the changeset viewer.