diff options
author | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:21:41 -0700 |
---|---|---|
committer | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:21:41 -0700 |
commit | 8879b125d26e8db1a5633de5a9c692eb2d1c4f83 (patch) | |
tree | c7259d85a991b83dfa85ab2e339360669fc1f58e /framework/src/suricata/src/util-logopenfile-tile.c | |
parent | 13d05bc8458758ee39cb829098241e89616717ee (diff) |
suricata checkin based on commit id a4bce14770beee46a537eda3c3f6e8e8565d5d0a
Change-Id: I9a214fa0ee95e58fc640e50bd604dac7f42db48f
Diffstat (limited to 'framework/src/suricata/src/util-logopenfile-tile.c')
-rw-r--r-- | framework/src/suricata/src/util-logopenfile-tile.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/framework/src/suricata/src/util-logopenfile-tile.c b/framework/src/suricata/src/util-logopenfile-tile.c new file mode 100644 index 00000000..c2414fc4 --- /dev/null +++ b/framework/src/suricata/src/util-logopenfile-tile.c @@ -0,0 +1,370 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * 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 Tom DeCanio <decanio.tom@gmail.com> + * \author Ken Steele, Tilera Corporation <suricata@tilera.com> + * + * File-like output for logging on Tilera PCIe cards (TILEncore-Gx) + * add the option to send logs across PCIe and then write the output + * files on the host system. + * + */ +#include <sys/types.h> + +#include "suricata-common.h" /* errno.h, string.h, etc. */ +#include "tm-modules.h" /* LogFileCtx */ +#include "conf.h" /* ConfNode, etc. */ +#include "util-atomic.h" +#include "util-logopenfile-tile.h" + +#ifdef __tile__ +#include <gxio/trio.h> +#include <mde-version.h> + +#if MDE_VERSION_CODE >= MDE_VERSION(4,1,0) +#include <gxpci/gxpci.h> +#else +#include <gxpci.h> +#endif + +/* + * Tilera trio (PCIe) configuration. + */ +static gxio_trio_context_t trio_context_body; +static gxio_trio_context_t* trio_context = &trio_context_body; +/* + * gxpci contexts used for log relay + */ +static gxpci_context_t gxpci_context_body; +static gxpci_context_t *gxpci_context = &gxpci_context_body; +/* The TRIO index. */ +static int trio_index = 0; + +/* The queue index of a packet queue. */ +static unsigned int queue_index = 0; + +/* The local PCIe MAC index. */ +static int loc_mac; + +/* + * Code for writing files over PCIe to host on Tilera TILEncore PCIe cards. + */ + +#define OP_OPEN 1 +#define OP_WRITE 2 +#define OP_CLOSE 3 + +/** Maximum number of commands in one PCIe function call */ +#define MAX_CMDS_BATCH 64 + +typedef struct { + uint32_t magic; + uint32_t fileno; + uint32_t op; + uint32_t seq; + uint32_t len; + uint32_t next_offset; + char buf[]; +} __attribute__((__packed__)) PcieMsg; + +static int gxpci_fileno = 0; +static int pcie_initialized = 0; +/* Allocate a Huge page of memory, registered with Trio, into which + data to be sent over PCIe is written. Each write starts at wc_pos. +*/ +static char *log_mem = NULL; +static uint64_t wr_pos; /* write position within log_mem */ + +static SCMutex raw_mutex __attribute__((aligned(64))); +static SCMutex pcie_mutex __attribute__((aligned(64))); +#define CHECK_SEQ_NUM 1 +#ifdef CHECK_SEQ_NUM +static uint32_t raw_seq = 0; +#endif +static uint32_t comps_rcvd = 0; +/* Block of memory registered with PCIe DMA engine as a source for + * PCIe data transfers. Must be <= Huge Page size (16 MB). + * Must be large enough that it can't wrap before first PCIe transfer + * has completed. + */ +#define PCIE_MEMORY_BLOCK_SIZE (4 * 1024 * 1024) + +/* Send a buffer over PCIe to Host memory. + * len must be smaller than one Packet Queue transfer block. + * TODO: Check errors + */ +static void TilePcieDMABuf(void *buf, uint32_t len) +{ + gxpci_comp_t comp[MAX_CMDS_BATCH]; + gxpci_cmd_t cmd; + int result; + int credits; + + SCMutexLock(&pcie_mutex); + +#ifdef CHECK_SEQ_NUM + ((PcieMsg *)buf)->seq = ++raw_seq; + __insn_mf(); +#endif + + /* Wait for credits to be available for more PCIe writes. */ + do { + result = gxpci_get_comps(gxpci_context, comp, 0, MAX_CMDS_BATCH); + if (result) { + if (unlikely(result == GXPCI_ERESET)) { + SCLogInfo("gxpci channel is reset"); + return; + } else { + __sync_fetch_and_add(&comps_rcvd, result); + } + } + + credits = gxpci_get_cmd_credits(gxpci_context); + if (unlikely(credits == GXPCI_ERESET)) { + SCLogInfo("gxpci channel is reset"); + return; + } + } while (credits == 0); + + cmd.buffer = buf; + /* Round transfer size up to next host cache-line. This will + * transfer more data, but is more efficient. + */ + cmd.size = (len + (CLS - 1)) & ~(CLS - 1); + + __insn_mf(); + + /* Loop until the command is sent. */ + do { + /* Send PCIe command to packet queue from tile to host. */ + result = gxpci_pq_t2h_cmd(gxpci_context, &cmd); + if (result == 0) + break; + if (result == GXPCI_ERESET) { + SCLogInfo("gxpci channel is reset"); + break; + } + /* Not enough credits to send command? */ + if (result == GXPCI_ECREDITS) + continue; + } while (1); + + SCMutexUnlock(&pcie_mutex); +} + +/* Allocate a buffer for data that can be sent over PCIe. Reserves + * space at the beginning for the Pcie msg. The buffer is allocated + * from a 4MB pool on one huge page. The allocation simply walks + * throught the buffer sequentially. This removes the need to free + * the buffers, as they simply age out. + */ +static PcieMsg *TilePcieAllocateBuffer(size_t size) +{ + size += sizeof(PcieMsg); + /* Round up to cache-line size */ + size = (size + (CLS - 1)) & ~(CLS - 1); + + PcieMsg *pmsg; + SCMutexLock(&raw_mutex); + pmsg = (PcieMsg *)&log_mem[wr_pos]; + wr_pos += size; + if (wr_pos > PCIE_MEMORY_BLOCK_SIZE) { + /* Don't have enough space at the end of the memory block, so + * wrap to the start. + */ + pmsg = (PcieMsg *)&log_mem[0]; + wr_pos = size; + + } + SCMutexUnlock(&raw_mutex); + + return pmsg; +} + +static void PcieWriteOpen(PcieFile *fp, const char *path, const char append) +{ + /* Need space for file name, file mode character and string termination */ + const int buffer_size = strlen(path) + 2; + + /* Allocate space in the PCIe output buffer */ + PcieMsg *p = TilePcieAllocateBuffer(buffer_size); + + p->magic = 5555; + p->fileno = fp->fileno; + p->op = OP_OPEN; + p->len = offsetof(PcieMsg, buf); + /* Format is one character Mode, followed by file path. */ + p->len += snprintf(p->buf, buffer_size, "%c%s", append, path); + + TilePcieDMABuf(p, p->len); +} + +static int TilePcieWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) +{ + PcieFile *fp = log_ctx->pcie_fp; + /* Allocate space in the PCIe output buffer */ + PcieMsg *p = TilePcieAllocateBuffer(buffer_len); + + p->magic = 5555; + p->fileno = fp->fileno; + p->op = OP_WRITE; + p->len = offsetof(PcieMsg, buf); + p->len += buffer_len; + p->next_offset = 0; + + /* Can remove the need for this memcpy later. */ + memcpy(p->buf, buffer, buffer_len); + + TilePcieDMABuf(p, p->len); + + return buffer_len; +} + +static PcieFile *TileOpenPcieFpInternal(const char *path, const char append_char) +{ + int result; + PcieFile *fp; + + /* Only initialize once */ + if (SCAtomicCompareAndSwap(&pcie_initialized, 0, 1)) { + SCMutexInit(&raw_mutex, NULL); + SCMutexInit(&pcie_mutex, NULL); + + SCLogInfo("Initializing Tile-Gx PCIe index %d / %d, queue: %d", + trio_index, loc_mac, queue_index); + + result = gxio_trio_init(trio_context, trio_index); + if (result < 0) { + pcie_initialized = 0; + SCLogError(SC_ERR_PCIE_INIT_FAILED, + "gxio_trio_init() failed: %d: %s", + result, gxio_strerror(result)); + return NULL; + } + + result = gxpci_init(trio_context, gxpci_context, trio_index, loc_mac); + if (result < 0) { + pcie_initialized = 0; + SCLogError(SC_ERR_PCIE_INIT_FAILED, + "gxpci_init() failed: %d: %s", + result, gxpci_strerror(result)); + return NULL; + } + + /* + * This indicates that we need to allocate an ASID ourselves, + * instead of using one that is allocated somewhere else. + */ + int asid = GXIO_ASID_NULL; + + result = gxpci_open_queue(gxpci_context, asid, GXPCI_PQ_T2H, 0, + queue_index, 0, 0); + if (result < 0) { + pcie_initialized = 0; + SCLogError(SC_ERR_PCIE_INIT_FAILED, + "gxpci_open_queue() failed: %d: %s", + result, gxpci_strerror(result)); + return NULL; + } + + /* + * Allocate and register data buffer + */ + size_t hugepagesz = tmc_alloc_get_huge_pagesize(); + tmc_alloc_t alloc = TMC_ALLOC_INIT; + tmc_alloc_set_huge(&alloc); + tmc_alloc_set_home(&alloc, TMC_ALLOC_HOME_HASH); + tmc_alloc_set_pagesize_exact(&alloc, hugepagesz); + log_mem = tmc_alloc_map(&alloc, hugepagesz); + BUG_ON(PCIE_MEMORY_BLOCK_SIZE > hugepagesz); + + result = gxpci_iomem_register(gxpci_context, log_mem, hugepagesz); + if (result < 0) { + pcie_initialized = 0; + SCLogError(SC_ERR_PCIE_INIT_FAILED, + "gxpci_iomem_register() failed: %d: %s", + result, gxpci_strerror(result)); + return NULL; + } + } + fp = SCMalloc(sizeof(PcieFile)); + if (fp == NULL) { + SCLogError(SC_ERR_PCIE_INIT_FAILED, + "Failed to Allocate memory for PCIe file pointer"); + + return NULL; + } + + /* Sequentially allocate File descriptor numbers. Not currently ever freed */ + fp->fileno = SCAtomicFetchAndAdd(&gxpci_fileno, 1); + PcieWriteOpen(fp, path, append_char); + + return fp; +} + +/** \brief Close a PCIe file + * \param PCIe file desriptor + */ +static void TileClosePcieFp(LogFileCtx *log_ctx) +{ + SCLogInfo("Closing Tile-Gx PCIe: %s", log_ctx->filename); + + /* TODO: Need to count open files and close when reaches zero. */ + SCMutexLock(&pcie_mutex); + + if (gxpci_context) { + gxpci_destroy(gxpci_context); + gxpci_context = NULL; + } + + SCMutexUnlock(&pcie_mutex); + + free(log_ctx->pcie_fp); +} + +/** \brief open the indicated file remotely over PCIe to a host + * \param path filesystem path to open + * \param append_setting open file with O_APPEND: "yes" or "no" + * \retval FILE* on success + * \retval NULL on error + */ +PcieFile *TileOpenPcieFp(LogFileCtx *log_ctx, const char *path, + const char *append_setting) +{ + PcieFile *ret = NULL; + if (strcasecmp(append_setting, "yes") == 0) { + ret = TileOpenPcieFpInternal(path, 'a'); + } else { + ret = TileOpenPcieFpInternal(path, 'w'); + } + + /* Override the default Write and Close functions + * with PCIe Write and Close functions. + */ + log_ctx->Write = TilePcieWrite; + log_ctx->Close = TileClosePcieFp; + + if (ret == NULL) + SCLogError(SC_ERR_FOPEN, "Error opening PCIe file: \"%s\": %s", + path, strerror(errno)); + return ret; +} + +#endif /* __tilegx__ */ |