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
/* 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;
|
|
}
|