From 8879b125d26e8db1a5633de5a9c692eb2d1c4f83 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Wed, 9 Sep 2015 22:21:41 -0700 Subject: suricata checkin based on commit id a4bce14770beee46a537eda3c3f6e8e8565d5d0a Change-Id: I9a214fa0ee95e58fc640e50bd604dac7f42db48f --- .../contrib/tile_pcie_logd/tile_pcie_logd.c | 370 +++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 framework/src/suricata/contrib/tile_pcie_logd/tile_pcie_logd.c (limited to 'framework/src/suricata/contrib/tile_pcie_logd/tile_pcie_logd.c') diff --git a/framework/src/suricata/contrib/tile_pcie_logd/tile_pcie_logd.c b/framework/src/suricata/contrib/tile_pcie_logd/tile_pcie_logd.c new file mode 100644 index 00000000..eb06f9e4 --- /dev/null +++ b/framework/src/suricata/contrib/tile_pcie_logd/tile_pcie_logd.c @@ -0,0 +1,370 @@ +/* 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 + * \author Tom DeCanio + * + * Host side of PCIe alert logging from Suricata running on a + * TILEncore-Gx card. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 + * 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; +} -- cgit 1.2.3-korg