mirror of https://github.com/OISF/suricata
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			371 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
		
		
			
		
	
	
			371 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
| 
								 
											12 years ago
										 
									 | 
							
								/* Copyright (C) 2013-2014 Tilera Corporation.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You can copy, redistribute or modify this Program under the terms of
							 | 
						||
| 
								 | 
							
								 * the GNU General Public License version 2 as published by the Free
							 | 
						||
| 
								 | 
							
								 * Software Foundation.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								 * but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						||
| 
								 | 
							
								 * GNU General Public License for more details.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You should have received a copy of the GNU General Public License
							 | 
						||
| 
								 | 
							
								 * version 2 along with this program; if not, write to the Free Software
							 | 
						||
| 
								 | 
							
								 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
							 | 
						||
| 
								 | 
							
								 * 02110-1301, USA.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * \file
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * \author Ken Steele, Tilera Corporation <suricata@tilera.com>
							 | 
						||
| 
								 | 
							
								 * \author Tom DeCanio <decanio.tom@gmail.com>
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Host side of PCIe alert logging from Suricata running on a
							 | 
						||
| 
								 | 
							
								 * TILEncore-Gx card.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <sys/mman.h>
							 | 
						||
| 
								 | 
							
								#include <sys/ioctl.h>
							 | 
						||
| 
								 | 
							
								#include <sys/time.h>
							 | 
						||
| 
								 | 
							
								#include <fcntl.h>
							 | 
						||
| 
								 | 
							
								#include <malloc.h>
							 | 
						||
| 
								 | 
							
								#include <unistd.h>
							 | 
						||
| 
								 | 
							
								#include <stdint.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								#include <time.h>
							 | 
						||
| 
								 | 
							
								#include <assert.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <asm/tilegxpci.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define CHECK_SEQ_NUM 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* The "/dev/tilegxpci%d" device to be used. */
							 | 
						||
| 
								 | 
							
								unsigned int card_index = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unsigned int debug = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * When set, drop all alerts rather than write to file. This is for
							 | 
						||
| 
								 | 
							
								 * testing performance on a file system that can't write files fast
							 | 
						||
| 
								 | 
							
								 * enough.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								unsigned int drop_alerts = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Packet queue index. */
							 | 
						||
| 
								 | 
							
								unsigned int queue_index;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Prefix added to all file paths sent from PCIe card. */
							 | 
						||
| 
								 | 
							
								char * path_prefix = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* By default, the host ring buffer is 4MB in size and it consists of
							 | 
						||
| 
								 | 
							
								 * 1024 entries of 4KB buffers. Modify GXPCI_HOST_PQ_RING_ENTRIES in
							 | 
						||
| 
								 | 
							
								 * <asm/tilegxpci.h> to change the size of each buffer. To increase
							 | 
						||
| 
								 | 
							
								 * the total ring buffer size, re-configure the host kernel using
							 | 
						||
| 
								 | 
							
								 * CONFIG_FORCE_MAX_ZONEORDER.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								#ifdef GXPCI_HOST_PQ_SEGMENT_ENTRIES
							 | 
						||
| 
								 | 
							
								/* New definitions for MDE 4.1.5 */
							 | 
						||
| 
								 | 
							
								#define RING_BUF_ELEMS      GXPCI_HOST_PQ_SEGMENT_ENTRIES
							 | 
						||
| 
								 | 
							
								#define RING_BUF_ELEM_SIZE  (HOST_PQ_SEGMENT_MAX_SIZE / GXPCI_HOST_PQ_SEGMENT_ENTRIES)
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								/* Definitions prior to MDE 4.1.5 */
							 | 
						||
| 
								 | 
							
								#define RING_BUF_ELEMS      GXPCI_HOST_PQ_RING_ENTRIES
							 | 
						||
| 
								 | 
							
								#define RING_BUF_ELEM_SIZE  (HOST_PQ_RING_BUF_MAX_SIZE / GXPCI_HOST_PQ_RING_ENTRIES)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*********************************************************************/
							 | 
						||
| 
								 | 
							
								/*                        Host-Side Packet Consumer                  */
							 | 
						||
| 
								 | 
							
								/*********************************************************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define TAIL_UPDATE_LIMIT_ENABLE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define OP_OPEN         1
							 | 
						||
| 
								 | 
							
								#define OP_WRITE        2
							 | 
						||
| 
								 | 
							
								#define OP_CLOSE        3
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct {
							 | 
						||
| 
								 | 
							
								    uint32_t    magic;
							 | 
						||
| 
								 | 
							
								    uint32_t    fileno;
							 | 
						||
| 
								 | 
							
								    uint32_t    op;
							 | 
						||
| 
								 | 
							
								    uint32_t    seq;
							 | 
						||
| 
								 | 
							
								    volatile uint32_t    len;
							 | 
						||
| 
								 | 
							
								    uint32_t    next_offset;
							 | 
						||
| 
								 | 
							
								    char        buf[];
							 | 
						||
| 
								 | 
							
								} TrioMsg;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct {
							 | 
						||
| 
								 | 
							
								    FILE *fd;
							 | 
						||
| 
								 | 
							
								} FDesc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define MAX_FDESC 1024
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static FDesc *fdesc[MAX_FDESC];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void run_pcie_logging(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    char dev_name[40];
							 | 
						||
| 
								 | 
							
								    int pq_fd;
							 | 
						||
| 
								 | 
							
								    unsigned int host_ring_buffer_size = RING_BUF_ELEMS * RING_BUF_ELEM_SIZE;
							 | 
						||
| 
								 | 
							
								    volatile TrioMsg *p;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    printf("Waiting for PCIe logging data from card %d on queue %d...\n", 
							 | 
						||
| 
								 | 
							
								           card_index, queue_index);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (path_prefix) {
							 | 
						||
| 
								 | 
							
								        printf("PCIe logging into directory: '%s'\n", path_prefix);
							 | 
						||
| 
								 | 
							
								        fflush(stdout);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* Open the packet queue file. */
							 | 
						||
| 
								 | 
							
								    snprintf(dev_name, sizeof(dev_name), "/dev/tilegxpci%d/packet_queue/t2h/%d",
							 | 
						||
| 
								 | 
							
								             card_index, queue_index);
							 | 
						||
| 
								 | 
							
								    do {
							 | 
						||
| 
								 | 
							
								        pq_fd = open(dev_name, O_RDWR);
							 | 
						||
| 
								 | 
							
								        if (pq_fd < 0) {
							 | 
						||
| 
								 | 
							
								            sleep(1);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } while (pq_fd < 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* mmap the register space. */
							 | 
						||
| 
								 | 
							
								    struct gxpci_host_pq_regs_app* pq_regs =
							 | 
						||
| 
								 | 
							
								        (struct gxpci_host_pq_regs_app*)
							 | 
						||
| 
								 | 
							
								        mmap(0, sizeof(struct gxpci_host_pq_regs_app),
							 | 
						||
| 
								 | 
							
								             PROT_READ | PROT_WRITE,
							 | 
						||
| 
								 | 
							
								             MAP_SHARED, pq_fd, TILEPCI_PACKET_QUEUE_INDICES_MMAP_OFFSET);
							 | 
						||
| 
								 | 
							
								    if (pq_regs == MAP_FAILED) {
							 | 
						||
| 
								 | 
							
								        fprintf(stderr, "Failed to mmap PCIe control registers.\n");
							 | 
						||
| 
								 | 
							
								        exit(EXIT_FAILURE);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* Configure and allocate the ring buffer for the receive queue. */
							 | 
						||
| 
								 | 
							
								    tilepci_packet_queue_info_t buf_info;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    buf_info.buf_size = RING_BUF_ELEM_SIZE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    int err = ioctl(pq_fd, TILEPCI_IOC_SET_PACKET_QUEUE_BUF, &buf_info);
							 | 
						||
| 
								 | 
							
								    if (err < 0) {
							 | 
						||
| 
								 | 
							
								        fprintf(stderr, "Failed TILEPCI_IOC_SET_PACKET_QUEUE_BUF: %s\n",
							 | 
						||
| 
								 | 
							
								                strerror(errno));
							 | 
						||
| 
								 | 
							
								        abort();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* On the host side, mmap the receive queue region. */
							 | 
						||
| 
								 | 
							
								    void* buffer =
							 | 
						||
| 
								 | 
							
								        mmap(0, host_ring_buffer_size, PROT_READ | PROT_WRITE,
							 | 
						||
| 
								 | 
							
								             MAP_SHARED, pq_fd, TILEPCI_PACKET_QUEUE_BUF_MMAP_OFFSET);
							 | 
						||
| 
								 | 
							
								    assert(buffer != MAP_FAILED);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* On the host side, mmap the queue status. */
							 | 
						||
| 
								 | 
							
								    struct tlr_pq_status *pq_status =
							 | 
						||
| 
								 | 
							
								        mmap(0, sizeof(struct tlr_pq_status), PROT_READ | PROT_WRITE,
							 | 
						||
| 
								 | 
							
								             MAP_SHARED, pq_fd, TILEPCI_PACKET_QUEUE_STS_MMAP_OFFSET);
							 | 
						||
| 
								 | 
							
								    assert(pq_status != MAP_FAILED);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pq_regs->consumer_index = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    uint64_t packet_count = 0;
							 | 
						||
| 
								 | 
							
								    volatile uint32_t write;
							 | 
						||
| 
								 | 
							
								    uint32_t read = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef CHECK_SEQ_NUM
							 | 
						||
| 
								 | 
							
								    uint32_t expect_seq = 1;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								#ifdef HOST_INTERRUPT_MODE
							 | 
						||
| 
								 | 
							
								    volatile uint32_t* producer_index = &(pq_status->drv_consumer_index);
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								    volatile uint32_t* producer_index = &(pq_regs->producer_index);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    volatile uint32_t* consumer_index = &(pq_regs->consumer_index);
							 | 
						||
| 
								 | 
							
								    volatile enum gxpci_chan_status_t* status = &(pq_status->status);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while (1) {
							 | 
						||
| 
								 | 
							
								        if (*status == GXPCI_CHAN_RESET) {
							 | 
						||
| 
								 | 
							
								            printf("Tile to Host PCIe logging channel was reset.\n");
							 | 
						||
| 
								 | 
							
								            fflush(stdout);
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Get packets off the ring buffer by accessing the receive queue at
							 | 
						||
| 
								 | 
							
								        // the new write index.
							 | 
						||
| 
								 | 
							
								        write = *producer_index;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        while (write != read) {
							 | 
						||
| 
								 | 
							
								            if (*status == GXPCI_CHAN_RESET) {
							 | 
						||
| 
								 | 
							
								                printf("Tile to Host PCIe logging channel was reset.\n");
							 | 
						||
| 
								 | 
							
								                fflush(stdout);
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            packet_count++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            p = (TrioMsg *)(buffer + ((read&(RING_BUF_ELEMS-1))*RING_BUF_ELEM_SIZE));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (debug) {
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "got a message\n");
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "p->magic: %d\n", p->magic);
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "p->fileno: %d\n", p->fileno);
							 | 
						||
| 
								 | 
							
								#ifdef CHECK_SEQ_NUM
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "p->seq: %d\n", p->seq);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "p->len: %d\n", p->len);
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "p->next_offset: %d\n", p->next_offset);
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "p->buf: ");
							 | 
						||
| 
								 | 
							
								                fwrite(&p->buf, sizeof(char), p->len - offsetof(TrioMsg, buf), stdout);
							 | 
						||
| 
								 | 
							
								                fprintf(stdout, "\n");
							 | 
						||
| 
								 | 
							
								                fflush(stdout);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef CHECK_SEQ_NUM
							 | 
						||
| 
								 | 
							
								            if (p->seq != expect_seq) {
							 | 
						||
| 
								 | 
							
								                /* Check for a reset before reporting a bad sequence
							 | 
						||
| 
								 | 
							
								                 * number to prevent confusing users. */
							 | 
						||
| 
								 | 
							
								                if (*status == GXPCI_CHAN_RESET) {
							 | 
						||
| 
								 | 
							
								                    printf("Tile to Host PCIe logging channel was reset.\n");
							 | 
						||
| 
								 | 
							
								                    fflush(stdout);
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                fprintf(stderr, "BAD sequence expected %d got %d\n", expect_seq, p->seq);
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            expect_seq = p->seq + 1;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            switch (p->op) {
							 | 
						||
| 
								 | 
							
								            case OP_OPEN:
							 | 
						||
| 
								 | 
							
								                if (p->fileno < MAX_FDESC) {
							 | 
						||
| 
								 | 
							
								                    fdesc[p->fileno] = malloc(sizeof(FDesc));
							 | 
						||
| 
								 | 
							
								                    if (fdesc[p->fileno]) {
							 | 
						||
| 
								 | 
							
								                        char mode[2];
							 | 
						||
| 
								 | 
							
								                        mode[0] = p->buf[0];
							 | 
						||
| 
								 | 
							
								                        mode[1] = '\0';
							 | 
						||
| 
								 | 
							
								                        char *file_name = (char *)&p->buf[1];
							 | 
						||
| 
								 | 
							
								                        if (path_prefix) {
							 | 
						||
| 
								 | 
							
								                            /* Added path_prefix to the start of the
							 | 
						||
| 
								 | 
							
								                             * file name. Added space for '\0' and '\'.
							 | 
						||
| 
								 | 
							
								                             * By default, no prefix is added. */
							 | 
						||
| 
								 | 
							
								                            int new_size = strlen(path_prefix) + strlen(file_name) + 1 + 1;
							 | 
						||
| 
								 | 
							
								                            char *new_name = malloc(new_size);
							 | 
						||
| 
								 | 
							
								                            if (!new_name) {
							 | 
						||
| 
								 | 
							
								                                fprintf(stderr, "Failed to allocate memory for %s/%s\n",
							 | 
						||
| 
								 | 
							
								                                        path_prefix, file_name);
							 | 
						||
| 
								 | 
							
								                                return;
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                            snprintf(new_name, new_size, "%s/%s", 
							 | 
						||
| 
								 | 
							
								                                     path_prefix, file_name);
							 | 
						||
| 
								 | 
							
								                            file_name = new_name;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                        if ((fdesc[p->fileno]->fd = fopen(file_name, mode)) == NULL) {
							 | 
						||
| 
								 | 
							
								                            fprintf(stderr, "Could not open %s: %s\n",
							 | 
						||
| 
								 | 
							
								                                    file_name, strerror(errno));
							 | 
						||
| 
								 | 
							
								                        } else {
							 | 
						||
| 
								 | 
							
								                            printf("Opened '%s' for logging.\n", file_name);
							 | 
						||
| 
								 | 
							
								                            fflush(stdout);
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    fprintf(stderr, "File number %d exceeds Max of %d\n", p->fileno, MAX_FDESC);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case OP_WRITE:
							 | 
						||
| 
								 | 
							
								                if (drop_alerts) {
							 | 
						||
| 
								 | 
							
								                    /* TODO: Report alert count periodically. */
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    if (fdesc[p->fileno] && fdesc[p->fileno]->fd) {
							 | 
						||
| 
								 | 
							
								                        fwrite(&p->buf, sizeof(char),
							 | 
						||
| 
								 | 
							
								                               p->len - offsetof(TrioMsg, buf),
							 | 
						||
| 
								 | 
							
								                               fdesc[p->fileno]->fd);
							 | 
						||
| 
								 | 
							
								                        fflush(fdesc[p->fileno]->fd);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case OP_CLOSE:
							 | 
						||
| 
								 | 
							
								                if (fdesc[p->fileno] && fdesc[p->fileno]->fd) {
							 | 
						||
| 
								 | 
							
								                    fclose( fdesc[p->fileno]->fd);
							 | 
						||
| 
								 | 
							
								                    free(fdesc[p->fileno]);
							 | 
						||
| 
								 | 
							
								                    fdesc[p->fileno] = NULL;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            read++;
							 | 
						||
| 
								 | 
							
								            /* Update the read index register to inform the tile side
							 | 
						||
| 
								 | 
							
								             * that the packet has been read. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef TAIL_UPDATE_LIMIT_ENABLE
							 | 
						||
| 
								 | 
							
								            if ((packet_count & 0x3f) == 0)
							 | 
						||
| 
								 | 
							
								                *consumer_index = read;
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								            *consumer_index = read;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Match argument list option.
							 | 
						||
| 
								 | 
							
								 * Options ending in '=' take an additional value, which may be
							 | 
						||
| 
								 | 
							
								 * attached in the same argument or detached in the following
							 | 
						||
| 
								 | 
							
								 * argument.
							 | 
						||
| 
								 | 
							
								 * @param arglist       Points to remaining argv, updated on match.
							 | 
						||
| 
								 | 
							
								 * @param option        The option to match, ending in '=' if it takes a value.
							 | 
						||
| 
								 | 
							
								 * @return              Value if option matches, NULL otherwise.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								char *shift_option(char ***arglist, const char* option)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    char** args = *arglist;
							 | 
						||
| 
								 | 
							
								    char* arg = args[0], **rest = &args[1];
							 | 
						||
| 
								 | 
							
								    int optlen = strlen(option);
							 | 
						||
| 
								 | 
							
								    char* val = arg+optlen;
							 | 
						||
| 
								 | 
							
								    if (option[optlen - 1] != '=') {
							 | 
						||
| 
								 | 
							
								        if (strcmp(arg, option))
							 | 
						||
| 
								 | 
							
								            return NULL;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        if (strncmp(arg, option, optlen-1))
							 | 
						||
| 
								 | 
							
								            return NULL;
							 | 
						||
| 
								 | 
							
								        if (arg[optlen- 1 ] == '\0')
							 | 
						||
| 
								 | 
							
								            val = *rest++;
							 | 
						||
| 
								 | 
							
								        else if (arg[optlen - 1] != '=')
							 | 
						||
| 
								 | 
							
								            return NULL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    *arglist = rest;
							 | 
						||
| 
								 | 
							
								    return val;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int main(int argc, char** argv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    char **args = &argv[1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*
							 | 
						||
| 
								 | 
							
								     * Scan command line options.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    while (*args) {
							 | 
						||
| 
								 | 
							
								        char* opt = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if ((opt = shift_option(&args, "--queue_index=")))
							 | 
						||
| 
								 | 
							
								            queue_index = strtoul(opt, NULL, 0);
							 | 
						||
| 
								 | 
							
								        else if ((opt = shift_option(&args, "--card=")))
							 | 
						||
| 
								 | 
							
								            card_index = strtoul(opt, NULL, 0);
							 | 
						||
| 
								 | 
							
								        else if ((opt = shift_option(&args, "--debug")))
							 | 
						||
| 
								 | 
							
								            debug = 1;
							 | 
						||
| 
								 | 
							
								        else if ((opt = shift_option(&args, "--drop")))
							 | 
						||
| 
								 | 
							
								            drop_alerts = 1;
							 | 
						||
| 
								 | 
							
								        else if ((opt = shift_option(&args, "--prefix=")))
							 | 
						||
| 
								 | 
							
								            path_prefix = opt;
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            fprintf(stderr, "Unknown option '%s'.\n", args[0]);
							 | 
						||
| 
								 | 
							
								            exit(EXIT_FAILURE);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    run_pcie_logging();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 |