/** * \brief Receives packets from a DAG interface. * * \param tv pointer to ThreadVars * \param data pointer to ErfDagThreadVars * \param slot slot containing task information * * \retval TM_ECODE_OK on success * \retval TM_ECODE_FAILED on failure */ TmEcode ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); ErfDagThreadVars *dtv = (ErfDagThreadVars *)data; uint32_t diff = 0; int err; uint8_t *top = NULL; uint32_t pkts_read = 0; TmSlot *s = (TmSlot *)slot; dtv->slot = s->slot_next; while (1) { if (suricata_ctl_flags & (SURICATA_STOP || SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } top = dag_advance_stream(dtv->dagfd, dtv->dagstream, &(dtv->btm)); if (top == NULL) { if (errno == EAGAIN) { if (dtv->dagstream & 0x1) { usleep(10 * 1000); dtv->btm = dtv->top; } continue; } else { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s when " "using dag_advance_stream", dtv->dagstream, dtv->dagname); SCReturnInt(TM_ECODE_FAILED); } } diff = top - dtv->btm; if (diff == 0) { continue; } assert(diff >= dag_record_size); err = ProcessErfDagRecords(dtv, top, &pkts_read); if (err == TM_ECODE_FAILED) { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s", dtv->dagstream, dtv->dagname); ReceiveErfDagCloseStream(dtv->dagfd, dtv->dagstream); SCReturnInt(TM_ECODE_FAILED); } SCLogDebug("Read %d records from stream: %d, DAG: %s", pkts_read, dtv->dagstream, dtv->dagname); } SCReturnInt(TM_ECODE_OK); }
/** * \brief Deinitializes the DAG card. * \param tv pointer to ThreadVars * \param data pointer that gets cast into PcapThreadVars for ptv */ TmEcode ReceiveErfDagThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; ReceiveErfDagCloseStream(ewtn->dagfd, ewtn->dagstream); SCReturnInt(TM_ECODE_OK); }
/** * \brief Thread entry function for reading ERF records from a DAG card. * * Reads a new ERF record the DAG input buffer and copies it to * an internal Suricata packet buffer -- similar to the way the * pcap packet handler works. * * We create new packet structures using PacketGetFromQueueOrAlloc * for each packet between the top and btm pointers except for * the first packet for which a Packet buffer is provided * from the packetpool. * * We always read up to dag_max_read_packets ERF packets from the * DAG buffer, but we might read less. This differs from the * ReceivePcap handler -- it will only read pkts up to a maximum * of either the packetpool count or the pcap_max_read_packets. * * \param tv pointer to ThreadVars * \param p data pointer * \param data * \param pq pointer to the PacketQueue (not used here) * \param postpq * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success. * \note We also use the packetpool hack first used in the source-pcap * handler so we don't keep producing packets without any dying. * This implies that if we are in this situation we run the risk * of dropping packets at the interface. */ TmEcode ReceiveErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); uint16_t packet_q_len = 0; uint32_t diff = 0; int err; uint8_t *top = NULL; uint32_t pkts_read = 0; assert(p); assert(pq); assert(postpq); ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; /* NOTE/JNM: Hack copied from source-pcap.c * * Make sure we have at least one packet in the packet pool, to * prevent us from alloc'ing packets at line rate */ while (packet_q_len == 0) { packet_q_len = PacketPoolSize(); if (packet_q_len == 0) { PacketPoolWait(); } } if (postpq == NULL) { ewtn->dag_max_read_packets = 1; } while(pkts_read == 0) { if (suricata_ctl_flags != 0) { break; } /* NOTE/JNM: This might not work well if we start restricting the * number of ERF records processed per call to a small number as * the over head required here could exceed the time it takes to * process a small number of ERF records. * * XXX/JNM: Possibly process the DAG stream buffer first if there * are ERF packets or else call dag_advance_stream and then process * the DAG stream buffer. */ top = dag_advance_stream(ewtn->dagfd, ewtn->dagstream, &(ewtn->btm)); if (NULL == top) { if((ewtn->dagstream & 0x1) && (errno == EAGAIN)) { usleep(10 * 1000); ewtn->btm = ewtn->top; continue; } else { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s when using dag_advance_stream", ewtn->dagstream, ewtn->dagname); SCReturnInt(TM_ECODE_FAILED); } } diff = top - ewtn->btm; if (diff == 0) { continue; } assert(diff >= dag_record_size); err = ProcessErfDagRecords(ewtn, p, top, postpq, &pkts_read); if (err == TM_ECODE_FAILED) { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); ReceiveErfDagCloseStream(ewtn->dagfd, ewtn->dagstream); SCReturnInt(err); } } SCLogDebug("Read %d records from stream: %d, DAG: %s", pkts_read, ewtn->dagstream, ewtn->dagname); if (suricata_ctl_flags != 0) { SCReturnInt(TM_ECODE_FAILED); } SCReturnInt(err); }