aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/util-logopenfile-tile.c
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
commit8879b125d26e8db1a5633de5a9c692eb2d1c4f83 (patch)
treec7259d85a991b83dfa85ab2e339360669fc1f58e /framework/src/suricata/src/util-logopenfile-tile.c
parent13d05bc8458758ee39cb829098241e89616717ee (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.c370
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__ */