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.
1844 lines
70 KiB
C
1844 lines
70 KiB
C
/* Copyright (C) 2017-2021 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 Napatech Inc.
|
|
* \author Phil Young <py@napatech.com>
|
|
*
|
|
*
|
|
*/
|
|
#include "suricata-common.h"
|
|
#include "suricata-plugin.h"
|
|
|
|
#include "suricata.h"
|
|
#include "util-device.h"
|
|
#include "util-cpu.h"
|
|
#include "util-byte.h"
|
|
#include "util-conf.h"
|
|
#include "threadvars.h"
|
|
#include "tm-threads.h"
|
|
#include "util-napatech.h"
|
|
#include "source-napatech.h"
|
|
#include "runmode-napatech.h"
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
|
|
/*
|
|
* counters to track the number of flows programmed on
|
|
* the adapter.
|
|
*/
|
|
typedef struct FlowStatsCounters_ {
|
|
uint16_t active_bypass_flows;
|
|
uint16_t total_bypass_flows;
|
|
} FlowStatsCounters;
|
|
|
|
static int bypass_supported;
|
|
int NapatechIsBypassSupported(void)
|
|
{
|
|
return bypass_supported;
|
|
}
|
|
|
|
/**
|
|
* \brief Returns the number of Napatech Adapters in the system.
|
|
*
|
|
* \return count of the Napatech adapters present in the system.
|
|
*/
|
|
int NapatechGetNumAdapters(void)
|
|
{
|
|
NtInfoStream_t hInfo;
|
|
NtInfo_t hInfoSys;
|
|
int status;
|
|
static int num_adapters = -1;
|
|
|
|
if (num_adapters == -1) {
|
|
if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
hInfoSys.cmd = NT_INFO_CMD_READ_SYSTEM;
|
|
if ((status = NT_InfoRead(hInfo, &hInfoSys)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
num_adapters = hInfoSys.u.system.data.numAdapters;
|
|
|
|
NT_InfoClose(hInfo);
|
|
}
|
|
|
|
return num_adapters;
|
|
}
|
|
|
|
/**
|
|
* \brief Verifies that the Napatech adapters support bypass.
|
|
*
|
|
* Attempts to opens a FlowStream on each adapter present in the system.
|
|
* If successful then bypass is supported
|
|
*
|
|
* \return 1 if Bypass functionality is supported; zero otherwise.
|
|
*/
|
|
int NapatechVerifyBypassSupport(void)
|
|
{
|
|
int status;
|
|
int adapter = 0;
|
|
int num_adapters = NapatechGetNumAdapters();
|
|
SCLogInfo("Found %d Napatech adapters.", num_adapters);
|
|
NtFlowStream_t hFlowStream;
|
|
|
|
if (!NapatechUseHWBypass()) {
|
|
/* HW Bypass is disabled in the conf file */
|
|
return 0;
|
|
}
|
|
|
|
for (adapter = 0; adapter < num_adapters; ++adapter) {
|
|
NtFlowAttr_t attr;
|
|
char flow_name[80];
|
|
|
|
NT_FlowOpenAttrInit(&attr);
|
|
NT_FlowOpenAttrSetAdapterNo(&attr, adapter);
|
|
|
|
snprintf(flow_name, sizeof(flow_name), "Flow stream %d", adapter);
|
|
SCLogInfo("Opening flow programming stream: %s\n", flow_name);
|
|
if ((status = NT_FlowOpen_Attr(&hFlowStream, flow_name, &attr)) != NT_SUCCESS) {
|
|
SCLogWarning("Napatech bypass functionality not supported by the FPGA version on "
|
|
"adapter %d - disabling support.",
|
|
adapter);
|
|
bypass_supported = 0;
|
|
return 0;
|
|
}
|
|
NT_FlowClose(hFlowStream);
|
|
}
|
|
|
|
bypass_supported = 1;
|
|
return bypass_supported;
|
|
}
|
|
|
|
/**
|
|
* \brief Updates statistic counters for Napatech FlowStats
|
|
*
|
|
* \param tv Thread variable to ThreadVars
|
|
* \param hInfo Handle to the Napatech InfoStream.
|
|
* \param hstat_stream Handle to the Napatech Statistics Stream.
|
|
* \param flow_counters The flow counters statistics to update.
|
|
* \param clear_stats Indicates if statistics on the card should be reset to zero.
|
|
*
|
|
*/
|
|
static void UpdateFlowStats(ThreadVars *tv, NtInfoStream_t hInfo, NtStatStream_t hstat_stream,
|
|
FlowStatsCounters flow_counters, int clear_stats)
|
|
{
|
|
NtStatistics_t hStat;
|
|
int status;
|
|
|
|
uint64_t programed = 0;
|
|
uint64_t removed = 0;
|
|
int adapter = 0;
|
|
|
|
for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) {
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_FLOW_V0;
|
|
hStat.u.flowData_v0.clear = clear_stats;
|
|
hStat.u.flowData_v0.adapterNo = adapter;
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(1);
|
|
}
|
|
programed = hStat.u.flowData_v0.learnDone;
|
|
removed = hStat.u.flowData_v0.unlearnDone + hStat.u.flowData_v0.automaticUnlearnDone +
|
|
hStat.u.flowData_v0.timeoutUnlearnDone;
|
|
}
|
|
|
|
StatsSetUI64(tv, flow_counters.active_bypass_flows, programed - removed);
|
|
StatsSetUI64(tv, flow_counters.total_bypass_flows, programed);
|
|
}
|
|
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*-----------------------------------------------------------------------------
|
|
* Statistics code
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
typedef struct PacketCounters_ {
|
|
uint16_t pkts;
|
|
uint16_t byte;
|
|
uint16_t drop_pkts;
|
|
uint16_t drop_byte;
|
|
} PacketCounters;
|
|
|
|
NapatechCurrentStats total_stats;
|
|
NapatechCurrentStats current_stats[MAX_STREAMS];
|
|
|
|
NapatechCurrentStats NapatechGetCurrentStats(uint16_t id)
|
|
{
|
|
|
|
return current_stats[id];
|
|
}
|
|
|
|
enum CONFIG_SPECIFIER {
|
|
CONFIG_SPECIFIER_UNDEFINED = 0,
|
|
CONFIG_SPECIFIER_RANGE,
|
|
CONFIG_SPECIFIER_INDIVIDUAL
|
|
};
|
|
|
|
//#define MAX_HOSTBUFFERS 8
|
|
|
|
/**
|
|
* \brief Test to see if any of the configured streams are active
|
|
*
|
|
* \param hInfo Handle to Napatech Info Stream.
|
|
* \param hStatsStream Handle to Napatech Statistics stream
|
|
* \param stream_config array of stream configuration structures
|
|
* \param num_inst
|
|
*
|
|
*/
|
|
static uint16_t TestStreamConfig(NtInfoStream_t hInfo, NtStatStream_t hstat_stream,
|
|
NapatechStreamConfig stream_config[], uint16_t num_inst)
|
|
{
|
|
uint16_t num_active = 0;
|
|
|
|
for (uint16_t inst = 0; inst < num_inst; ++inst) {
|
|
int status;
|
|
NtStatistics_t stat; // Stat handle.
|
|
|
|
/* Check to see if it is an active stream */
|
|
memset(&stat, 0, sizeof(NtStatistics_t));
|
|
|
|
/* Read usage data for the chosen stream ID */
|
|
stat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
|
|
stat.u.usageData_v0.streamid = (uint8_t)stream_config[inst].stream_id;
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &stat)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return 0;
|
|
}
|
|
|
|
if (stat.u.usageData_v0.data.numHostBufferUsed > 0) {
|
|
stream_config[inst].is_active = true;
|
|
num_active++;
|
|
} else {
|
|
stream_config[inst].is_active = false;
|
|
}
|
|
}
|
|
|
|
return num_active;
|
|
}
|
|
|
|
/**
|
|
* \brief Updates Napatech packet counters
|
|
*
|
|
* \param tv Pointer to ThreadVars structure
|
|
* \param hInfo Handle to Napatech Info Stream.
|
|
* \param hstat_stream Handle to Napatech Statistics stream
|
|
* \param num_streams the number of streams that are currently active
|
|
* \param stream_config array of stream configuration structures
|
|
* \param total_counters - cumulative count of all packets received.
|
|
* \param dispatch_host, - Count of packets that were delivered to the host buffer
|
|
* \param dispatch_drop - count of packets that were dropped as a result of a rule
|
|
* \param dispatch_fwd - count of packets forwarded out the egress port as the result of a rule
|
|
* \param is_inline - are we running in inline mode?
|
|
* \param enable_stream_stats - are per thread/stream statistics enabled.
|
|
* \param stream_counters - counters for each thread/stream configured.
|
|
*
|
|
* \return The number of active streams that were updated.
|
|
*
|
|
*/
|
|
static uint32_t UpdateStreamStats(ThreadVars *tv, NtInfoStream_t hInfo, NtStatStream_t hstat_stream,
|
|
uint16_t num_streams, NapatechStreamConfig stream_config[], PacketCounters total_counters,
|
|
PacketCounters dispatch_host, PacketCounters dispatch_drop, PacketCounters dispatch_fwd,
|
|
int is_inline, int enable_stream_stats, PacketCounters stream_counters[])
|
|
{
|
|
static uint64_t rxPktsStart[MAX_STREAMS] = { 0 };
|
|
static uint64_t rxByteStart[MAX_STREAMS] = { 0 };
|
|
static uint64_t dropPktStart[MAX_STREAMS] = { 0 };
|
|
static uint64_t dropByteStart[MAX_STREAMS] = { 0 };
|
|
|
|
int status;
|
|
NtInfo_t hStreamInfo;
|
|
NtStatistics_t hStat; // Stat handle.
|
|
|
|
/* Query the system to get the number of streams currently instantiated */
|
|
hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM;
|
|
if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
uint16_t num_active;
|
|
if ((num_active = TestStreamConfig(hInfo, hstat_stream, stream_config, num_streams)) == 0) {
|
|
/* None of the configured streams are active */
|
|
return 0;
|
|
}
|
|
|
|
/* At least one stream is active so proceed with the stats. */
|
|
uint16_t inst_id = 0;
|
|
uint32_t stream_cnt = 0;
|
|
for (stream_cnt = 0; stream_cnt < num_streams; ++stream_cnt) {
|
|
while (inst_id < num_streams) {
|
|
if (stream_config[inst_id].is_active) {
|
|
break;
|
|
} else {
|
|
++inst_id;
|
|
}
|
|
}
|
|
if (inst_id == num_streams)
|
|
break;
|
|
|
|
/* Read usage data for the chosen stream ID */
|
|
memset(&hStat, 0, sizeof(NtStatistics_t));
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
|
|
hStat.u.usageData_v0.streamid = (uint8_t)stream_config[inst_id].stream_id;
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return 0;
|
|
}
|
|
|
|
uint16_t stream_id = stream_config[inst_id].stream_id;
|
|
if (stream_config[inst_id].is_active) {
|
|
uint64_t rx_pkts_total = 0;
|
|
uint64_t rx_byte_total = 0;
|
|
uint64_t drop_pkts_total = 0;
|
|
uint64_t drop_byte_total = 0;
|
|
|
|
for (uint32_t hbCount = 0; hbCount < hStat.u.usageData_v0.data.numHostBufferUsed;
|
|
hbCount++) {
|
|
if (unlikely(!stream_config[inst_id].initialized)) {
|
|
rxPktsStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.frames;
|
|
rxByteStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.bytes;
|
|
dropPktStart[stream_id] +=
|
|
hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames;
|
|
dropByteStart[stream_id] +=
|
|
hStat.u.usageData_v0.data.hb[hbCount].stat.drop.bytes;
|
|
stream_config[inst_id].initialized = true;
|
|
} else {
|
|
rx_pkts_total += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.frames;
|
|
rx_byte_total += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.bytes;
|
|
drop_pkts_total += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames;
|
|
drop_byte_total += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.bytes;
|
|
}
|
|
}
|
|
|
|
current_stats[stream_id].current_packets = rx_pkts_total - rxPktsStart[stream_id];
|
|
current_stats[stream_id].current_bytes = rx_byte_total - rxByteStart[stream_id];
|
|
current_stats[stream_id].current_drop_packets =
|
|
drop_pkts_total - dropPktStart[stream_id];
|
|
current_stats[stream_id].current_drop_bytes =
|
|
drop_byte_total - dropByteStart[stream_id];
|
|
}
|
|
|
|
if (enable_stream_stats) {
|
|
StatsSetUI64(
|
|
tv, stream_counters[inst_id].pkts, current_stats[stream_id].current_packets);
|
|
StatsSetUI64(tv, stream_counters[inst_id].byte, current_stats[stream_id].current_bytes);
|
|
StatsSetUI64(tv, stream_counters[inst_id].drop_pkts,
|
|
current_stats[stream_id].current_drop_packets);
|
|
StatsSetUI64(tv, stream_counters[inst_id].drop_byte,
|
|
current_stats[stream_id].current_drop_bytes);
|
|
}
|
|
|
|
++inst_id;
|
|
}
|
|
|
|
uint32_t stream_id;
|
|
for (stream_id = 0; stream_id < num_streams; ++stream_id) {
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
total_stats.current_packets += current_stats[stream_id].current_packets;
|
|
total_stats.current_bytes += current_stats[stream_id].current_bytes;
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
total_stats.current_drop_packets += current_stats[stream_id].current_drop_packets;
|
|
total_stats.current_drop_bytes += current_stats[stream_id].current_drop_bytes;
|
|
}
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
StatsSetUI64(tv, total_counters.pkts, total_stats.current_packets);
|
|
StatsSetUI64(tv, total_counters.byte, total_stats.current_bytes);
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
StatsSetUI64(tv, total_counters.drop_pkts, total_stats.current_drop_packets);
|
|
StatsSetUI64(tv, total_counters.drop_byte, total_stats.current_drop_bytes);
|
|
|
|
total_stats.current_packets = 0;
|
|
total_stats.current_bytes = 0;
|
|
total_stats.current_drop_packets = 0;
|
|
total_stats.current_drop_bytes = 0;
|
|
|
|
/* Read usage data for the chosen stream ID */
|
|
memset(&hStat, 0, sizeof(NtStatistics_t));
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V3;
|
|
hStat.u.query_v3.clear = 0;
|
|
#else /* NAPATECH_ENABLE_BYPASS */
|
|
/* Older versions of the API have a different structure. */
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V2;
|
|
hStat.u.query_v2.clear = 0;
|
|
#endif /* !NAPATECH_ENABLE_BYPASS */
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
if (status == NT_STATUS_TIMEOUT) {
|
|
SCLogInfo("Statistics timed out - will retry next time.");
|
|
return 0;
|
|
} else {
|
|
NAPATECH_ERROR(status);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
|
|
int adapter = 0;
|
|
uint64_t total_dispatch_host_pkts = 0;
|
|
uint64_t total_dispatch_host_byte = 0;
|
|
uint64_t total_dispatch_drop_pkts = 0;
|
|
uint64_t total_dispatch_drop_byte = 0;
|
|
uint64_t total_dispatch_fwd_pkts = 0;
|
|
uint64_t total_dispatch_fwd_byte = 0;
|
|
|
|
for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) {
|
|
total_dispatch_host_pkts +=
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].pkts;
|
|
total_dispatch_host_byte +=
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].octets;
|
|
|
|
total_dispatch_drop_pkts +=
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].pkts +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].pkts;
|
|
total_dispatch_drop_byte +=
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].octets +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].octets;
|
|
|
|
total_dispatch_fwd_pkts +=
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].pkts +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[4].pkts;
|
|
total_dispatch_fwd_byte +=
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].octets +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[4].octets;
|
|
|
|
total_stats.current_packets +=
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].pkts +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].pkts +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].pkts +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].pkts;
|
|
|
|
total_stats.current_bytes =
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].octets +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].octets +
|
|
hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].octets;
|
|
}
|
|
|
|
StatsSetUI64(tv, dispatch_host.pkts, total_dispatch_host_pkts);
|
|
StatsSetUI64(tv, dispatch_host.byte, total_dispatch_host_byte);
|
|
|
|
StatsSetUI64(tv, dispatch_drop.pkts, total_dispatch_drop_pkts);
|
|
StatsSetUI64(tv, dispatch_drop.byte, total_dispatch_drop_byte);
|
|
|
|
if (is_inline) {
|
|
StatsSetUI64(tv, dispatch_fwd.pkts, total_dispatch_fwd_pkts);
|
|
StatsSetUI64(tv, dispatch_fwd.byte, total_dispatch_fwd_byte);
|
|
}
|
|
|
|
StatsSetUI64(tv, total_counters.pkts, total_stats.current_packets);
|
|
StatsSetUI64(tv, total_counters.byte, total_stats.current_bytes);
|
|
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
return num_active;
|
|
}
|
|
|
|
/**
|
|
* \brief Statistics processing loop
|
|
*
|
|
* Instantiated on the stats thread. Periodically retrieves
|
|
* statistics from the Napatech card and updates the packet counters
|
|
*
|
|
* \param arg Pointer that is cast into a ThreadVars structure
|
|
*/
|
|
static void *NapatechStatsLoop(void *arg)
|
|
{
|
|
ThreadVars *tv = (ThreadVars *)arg;
|
|
|
|
int status;
|
|
NtInfoStream_t hInfo;
|
|
NtStatStream_t hstat_stream;
|
|
int is_inline = 0;
|
|
int enable_stream_stats = 0;
|
|
PacketCounters stream_counters[MAX_STREAMS];
|
|
|
|
if (ConfGetBool("napatech.inline", &is_inline) == 0) {
|
|
is_inline = 0;
|
|
}
|
|
|
|
if (ConfGetBool("napatech.enable-stream-stats", &enable_stream_stats) == 0) {
|
|
/* default is "no" */
|
|
enable_stream_stats = 0;
|
|
}
|
|
|
|
NapatechStreamConfig stream_config[MAX_STREAMS];
|
|
uint16_t stream_cnt = NapatechGetStreamConfig(stream_config);
|
|
|
|
/* Open the info and Statistics */
|
|
if ((status = NT_InfoOpen(&hInfo, "StatsLoopInfoStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return NULL;
|
|
}
|
|
|
|
if ((status = NT_StatOpen(&hstat_stream, "StatsLoopStatsStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return NULL;
|
|
}
|
|
|
|
NtStatistics_t hStat;
|
|
memset(&hStat, 0, sizeof(NtStatistics_t));
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V3;
|
|
hStat.u.query_v3.clear = 1;
|
|
#else /* NAPATECH_ENABLE_BYPASS */
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V2;
|
|
hStat.u.query_v2.clear = 1;
|
|
#endif /* !NAPATECH_ENABLE_BYPASS */
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return 0;
|
|
}
|
|
|
|
PacketCounters total_counters;
|
|
memset(&total_counters, 0, sizeof(total_counters));
|
|
|
|
PacketCounters dispatch_host;
|
|
memset(&dispatch_host, 0, sizeof(dispatch_host));
|
|
|
|
PacketCounters dispatch_drop;
|
|
memset(&dispatch_drop, 0, sizeof(dispatch_drop));
|
|
|
|
PacketCounters dispatch_fwd;
|
|
memset(&dispatch_fwd, 0, sizeof(dispatch_fwd));
|
|
|
|
total_counters.pkts = StatsRegisterCounter("napa_total.pkts", tv);
|
|
dispatch_host.pkts = StatsRegisterCounter("napa_dispatch_host.pkts", tv);
|
|
dispatch_drop.pkts = StatsRegisterCounter("napa_dispatch_drop.pkts", tv);
|
|
if (is_inline) {
|
|
dispatch_fwd.pkts = StatsRegisterCounter("napa_dispatch_fwd.pkts", tv);
|
|
}
|
|
|
|
total_counters.byte = StatsRegisterCounter("napa_total.byte", tv);
|
|
dispatch_host.byte = StatsRegisterCounter("napa_dispatch_host.byte", tv);
|
|
dispatch_drop.byte = StatsRegisterCounter("napa_dispatch_drop.byte", tv);
|
|
if (is_inline) {
|
|
dispatch_fwd.byte = StatsRegisterCounter("napa_dispatch_fwd.byte", tv);
|
|
}
|
|
|
|
total_counters.drop_pkts = StatsRegisterCounter("napa_total.overflow_drop_pkts", tv);
|
|
total_counters.drop_byte = StatsRegisterCounter("napa_total.overflow_drop_byte", tv);
|
|
|
|
if (enable_stream_stats) {
|
|
for (int i = 0; i < stream_cnt; ++i) {
|
|
char *pkts_buf = SCCalloc(1, 32);
|
|
if (unlikely(pkts_buf == NULL)) {
|
|
FatalError("Failed to allocate memory for NAPATECH stream counter.");
|
|
}
|
|
|
|
snprintf(pkts_buf, 32, "napa%d.pkts", stream_config[i].stream_id);
|
|
stream_counters[i].pkts = StatsRegisterCounter(pkts_buf, tv);
|
|
|
|
char *byte_buf = SCCalloc(1, 32);
|
|
if (unlikely(byte_buf == NULL)) {
|
|
FatalError("Failed to allocate memory for NAPATECH stream counter.");
|
|
}
|
|
snprintf(byte_buf, 32, "napa%d.bytes", stream_config[i].stream_id);
|
|
stream_counters[i].byte = StatsRegisterCounter(byte_buf, tv);
|
|
|
|
char *drop_pkts_buf = SCCalloc(1, 32);
|
|
if (unlikely(drop_pkts_buf == NULL)) {
|
|
FatalError("Failed to allocate memory for NAPATECH stream counter.");
|
|
}
|
|
snprintf(drop_pkts_buf, 32, "napa%d.drop_pkts", stream_config[i].stream_id);
|
|
stream_counters[i].drop_pkts = StatsRegisterCounter(drop_pkts_buf, tv);
|
|
|
|
char *drop_byte_buf = SCCalloc(1, 32);
|
|
if (unlikely(drop_byte_buf == NULL)) {
|
|
FatalError("Failed to allocate memory for NAPATECH stream counter.");
|
|
}
|
|
snprintf(drop_byte_buf, 32, "napa%d.drop_byte", stream_config[i].stream_id);
|
|
stream_counters[i].drop_byte = StatsRegisterCounter(drop_byte_buf, tv);
|
|
}
|
|
}
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
FlowStatsCounters flow_counters;
|
|
if (bypass_supported) {
|
|
flow_counters.active_bypass_flows = StatsRegisterCounter("napa_bypass.active_flows", tv);
|
|
flow_counters.total_bypass_flows = StatsRegisterCounter("napa_bypass.total_flows", tv);
|
|
}
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
StatsSetupPrivate(tv);
|
|
|
|
StatsSetUI64(tv, total_counters.pkts, 0);
|
|
StatsSetUI64(tv, total_counters.byte, 0);
|
|
StatsSetUI64(tv, total_counters.drop_pkts, 0);
|
|
StatsSetUI64(tv, total_counters.drop_byte, 0);
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
if (bypass_supported) {
|
|
StatsSetUI64(tv, dispatch_host.pkts, 0);
|
|
StatsSetUI64(tv, dispatch_drop.pkts, 0);
|
|
|
|
if (is_inline) {
|
|
StatsSetUI64(tv, dispatch_fwd.pkts, 0);
|
|
}
|
|
|
|
StatsSetUI64(tv, dispatch_host.byte, 0);
|
|
StatsSetUI64(tv, dispatch_drop.byte, 0);
|
|
if (is_inline) {
|
|
StatsSetUI64(tv, dispatch_fwd.byte, 0);
|
|
}
|
|
|
|
if (enable_stream_stats) {
|
|
for (int i = 0; i < stream_cnt; ++i) {
|
|
StatsSetUI64(tv, stream_counters[i].pkts, 0);
|
|
StatsSetUI64(tv, stream_counters[i].byte, 0);
|
|
StatsSetUI64(tv, stream_counters[i].drop_pkts, 0);
|
|
StatsSetUI64(tv, stream_counters[i].drop_byte, 0);
|
|
}
|
|
}
|
|
|
|
StatsSetUI64(tv, flow_counters.active_bypass_flows, 0);
|
|
StatsSetUI64(tv, flow_counters.total_bypass_flows, 0);
|
|
UpdateFlowStats(tv, hInfo, hstat_stream, flow_counters, 1);
|
|
}
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
uint32_t num_active = UpdateStreamStats(tv, hInfo, hstat_stream, stream_cnt, stream_config,
|
|
total_counters, dispatch_host, dispatch_drop, dispatch_fwd, is_inline,
|
|
enable_stream_stats, stream_counters);
|
|
|
|
if (!NapatechIsAutoConfigEnabled() && (num_active < stream_cnt)) {
|
|
SCLogInfo("num_active: %d, stream_cnt: %d", num_active, stream_cnt);
|
|
SCLogWarning("Some or all of the configured streams are not created. Proceeding with "
|
|
"active streams.");
|
|
}
|
|
|
|
TmThreadsSetFlag(tv, THV_INIT_DONE | THV_RUNNING);
|
|
while (1) {
|
|
if (TmThreadsCheckFlag(tv, THV_KILL)) {
|
|
SCLogDebug("NapatechStatsLoop THV_KILL detected");
|
|
break;
|
|
}
|
|
|
|
UpdateStreamStats(tv, hInfo, hstat_stream, stream_cnt, stream_config, total_counters,
|
|
dispatch_host, dispatch_drop, dispatch_fwd, is_inline, enable_stream_stats,
|
|
stream_counters);
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
if (bypass_supported) {
|
|
UpdateFlowStats(tv, hInfo, hstat_stream, flow_counters, 0);
|
|
}
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
StatsSyncCountersIfSignalled(tv);
|
|
usleep(1000000);
|
|
}
|
|
|
|
/* CLEAN UP NT Resources and Close the info stream */
|
|
if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return NULL;
|
|
}
|
|
|
|
/* Close the statistics stream */
|
|
if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return NULL;
|
|
}
|
|
|
|
SCLogDebug("Exiting NapatechStatsLoop");
|
|
TmThreadsSetFlag(tv, THV_RUNNING_DONE);
|
|
TmThreadWaitForFlag(tv, THV_DEINIT);
|
|
TmThreadsSetFlag(tv, THV_CLOSED);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//#define MAX_STREAMS 256
|
|
//#define HB_HIGHWATER 2048 //1982
|
|
|
|
/**
|
|
* \brief Tests whether a particular stream_id is actively registered
|
|
*
|
|
* \param stream_id - ID of the stream to look up
|
|
* \param num_registered - The total number of registered streams
|
|
* \param registered_streams - An array containing actively registered streams.
|
|
*
|
|
* \return Bool indicating is the specified stream is registered.
|
|
*
|
|
*/
|
|
static bool RegisteredStream(
|
|
uint16_t stream_id, uint16_t num_registered, NapatechStreamConfig registered_streams[])
|
|
{
|
|
for (uint16_t reg_id = 0; reg_id < num_registered; ++reg_id) {
|
|
if (stream_id == registered_streams[reg_id].stream_id) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* \brief Count the number of worker threads defined in the conf file.
|
|
*
|
|
* \return - The number of worker threads defined by the configuration
|
|
*/
|
|
static uint32_t CountWorkerThreads(void)
|
|
{
|
|
int worker_count = 0;
|
|
|
|
ConfNode *affinity;
|
|
ConfNode *root = ConfGetNode("threading.cpu-affinity");
|
|
|
|
if (root != NULL) {
|
|
|
|
TAILQ_FOREACH (affinity, &root->head, next) {
|
|
if (strcmp(affinity->val, "decode-cpu-set") == 0 ||
|
|
strcmp(affinity->val, "stream-cpu-set") == 0 ||
|
|
strcmp(affinity->val, "reject-cpu-set") == 0 ||
|
|
strcmp(affinity->val, "output-cpu-set") == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(affinity->val, "worker-cpu-set") == 0) {
|
|
ConfNode *node = ConfNodeLookupChild(affinity->head.tqh_first, "cpu");
|
|
ConfNode *lnode;
|
|
|
|
enum CONFIG_SPECIFIER cpu_spec = CONFIG_SPECIFIER_UNDEFINED;
|
|
|
|
TAILQ_FOREACH (lnode, &node->head, next) {
|
|
uint8_t start, end;
|
|
char *end_str;
|
|
if (strncmp(lnode->val, "all", 4) == 0) {
|
|
/* check that the sting in the config file is correctly specified */
|
|
if (cpu_spec != CONFIG_SPECIFIER_UNDEFINED) {
|
|
FatalError("Only one Napatech port specifier type allowed.");
|
|
}
|
|
cpu_spec = CONFIG_SPECIFIER_RANGE;
|
|
worker_count = UtilCpuGetNumProcessorsConfigured();
|
|
} else if ((end_str = strchr(lnode->val, '-'))) {
|
|
/* check that the sting in the config file is correctly specified */
|
|
if (cpu_spec != CONFIG_SPECIFIER_UNDEFINED) {
|
|
FatalError("Only one Napatech port specifier type allowed.");
|
|
}
|
|
cpu_spec = CONFIG_SPECIFIER_RANGE;
|
|
|
|
if (StringParseUint8(&start, 10, end_str - lnode->val,
|
|
(const char *)lnode->val) < 0) {
|
|
FatalError("Napatech invalid"
|
|
" worker range start: '%s'",
|
|
lnode->val);
|
|
}
|
|
if (StringParseUint8(&end, 10, 0, (const char *)(end_str + 1)) < 0) {
|
|
FatalError("Napatech invalid"
|
|
" worker range end: '%s'",
|
|
(end_str != NULL) ? (const char *)(end_str + 1) : "Null");
|
|
}
|
|
if (end < start) {
|
|
FatalError("Napatech invalid"
|
|
" worker range start: '%d' is greater than end: '%d'",
|
|
start, end);
|
|
}
|
|
worker_count = end - start + 1;
|
|
|
|
} else {
|
|
/* check that the sting in the config file is correctly specified */
|
|
if (cpu_spec == CONFIG_SPECIFIER_RANGE) {
|
|
FatalError("Napatech port range specifiers cannot be combined with "
|
|
"individual stream specifiers.");
|
|
}
|
|
cpu_spec = CONFIG_SPECIFIER_INDIVIDUAL;
|
|
++worker_count;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return worker_count;
|
|
}
|
|
|
|
/**
|
|
* \brief Reads and parses the stream configuration defined in the config file.
|
|
*
|
|
* \param stream_config - array to be filled in with active stream info.
|
|
*
|
|
* \return the number of streams configured or -1 if an error occurred
|
|
*
|
|
*/
|
|
int NapatechGetStreamConfig(NapatechStreamConfig stream_config[])
|
|
{
|
|
int status;
|
|
char error_buffer[80]; // Error buffer
|
|
NtStatStream_t hstat_stream;
|
|
NtStatistics_t hStat; // Stat handle.
|
|
NtInfoStream_t info_stream;
|
|
NtInfo_t info;
|
|
uint16_t instance_cnt = 0;
|
|
int use_all_streams = 0;
|
|
int set_cpu_affinity = 0;
|
|
ConfNode *ntstreams;
|
|
uint16_t stream_id = 0;
|
|
uint8_t start = 0;
|
|
uint8_t end = 0;
|
|
|
|
for (uint16_t i = 0; i < MAX_STREAMS; ++i) {
|
|
stream_config[i].stream_id = 0;
|
|
stream_config[i].is_active = false;
|
|
stream_config[i].initialized = false;
|
|
}
|
|
|
|
if (ConfGetBool("napatech.use-all-streams", &use_all_streams) == 0) {
|
|
/* default is "no" */
|
|
use_all_streams = 0;
|
|
}
|
|
|
|
if ((status = NT_InfoOpen(&info_stream, "SuricataStreamInfo")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return -1;
|
|
}
|
|
|
|
if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return -1;
|
|
}
|
|
|
|
if (use_all_streams) {
|
|
info.cmd = NT_INFO_CMD_READ_STREAM;
|
|
if ((status = NT_InfoRead(info_stream, &info)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return -1;
|
|
}
|
|
|
|
while (instance_cnt < info.u.stream.data.count) {
|
|
|
|
/*
|
|
* For each stream ID query the number of host-buffers used by
|
|
* the stream. If zero, then that streamID is not used; skip
|
|
* over it and continue until we get a streamID with a non-zero
|
|
* count of the host-buffers.
|
|
*/
|
|
memset(&hStat, 0, sizeof(NtStatistics_t));
|
|
|
|
/* Read usage data for the chosen stream ID */
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
|
|
hStat.u.usageData_v0.streamid = (uint8_t)stream_id;
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
/* Get the status code as text */
|
|
NT_ExplainError(status, error_buffer, sizeof(error_buffer));
|
|
SCLogError("NT_StatRead() failed: %s\n", error_buffer);
|
|
return -1;
|
|
}
|
|
|
|
if (hStat.u.usageData_v0.data.numHostBufferUsed == 0) {
|
|
++stream_id;
|
|
continue;
|
|
}
|
|
|
|
/* if we get here it is an active stream */
|
|
stream_config[instance_cnt].stream_id = stream_id++;
|
|
stream_config[instance_cnt].is_active = true;
|
|
instance_cnt++;
|
|
}
|
|
|
|
} else {
|
|
(void)ConfGetBool("threading.set-cpu-affinity", &set_cpu_affinity);
|
|
if (NapatechIsAutoConfigEnabled() && (set_cpu_affinity == 1)) {
|
|
start = 0;
|
|
end = CountWorkerThreads() - 1;
|
|
} else {
|
|
/* When not using the default streams we need to
|
|
* parse the array of streams from the conf */
|
|
if ((ntstreams = ConfGetNode("napatech.streams")) == NULL) {
|
|
SCLogError("Failed retrieving napatech.streams from Config");
|
|
if (NapatechIsAutoConfigEnabled() && (set_cpu_affinity == 0)) {
|
|
SCLogError("if set-cpu-affinity: no in conf then napatech.streams must be "
|
|
"defined");
|
|
}
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Loop through all stream numbers in the array and register the devices */
|
|
ConfNode *stream;
|
|
enum CONFIG_SPECIFIER stream_spec = CONFIG_SPECIFIER_UNDEFINED;
|
|
instance_cnt = 0;
|
|
|
|
TAILQ_FOREACH (stream, &ntstreams->head, next) {
|
|
|
|
if (stream == NULL) {
|
|
SCLogError("Couldn't Parse Stream Configuration");
|
|
return -1;
|
|
}
|
|
|
|
char *end_str = strchr(stream->val, '-');
|
|
if (end_str) {
|
|
if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) {
|
|
SCLogError("Only one Napatech stream range specifier allowed.");
|
|
return -1;
|
|
}
|
|
stream_spec = CONFIG_SPECIFIER_RANGE;
|
|
|
|
if (StringParseUint8(
|
|
&start, 10, end_str - stream->val, (const char *)stream->val) < 0) {
|
|
FatalError("Napatech invalid "
|
|
"stream id start: '%s'",
|
|
stream->val);
|
|
}
|
|
if (StringParseUint8(&end, 10, 0, (const char *)(end_str + 1)) < 0) {
|
|
FatalError("Napatech invalid "
|
|
"stream id end: '%s'",
|
|
(end_str != NULL) ? (const char *)(end_str + 1) : "Null");
|
|
}
|
|
} else {
|
|
if (stream_spec == CONFIG_SPECIFIER_RANGE) {
|
|
FatalError("Napatech range and individual specifiers cannot be combined.");
|
|
}
|
|
stream_spec = CONFIG_SPECIFIER_INDIVIDUAL;
|
|
if (StringParseUint8(&stream_config[instance_cnt].stream_id, 10, 0,
|
|
(const char *)stream->val) < 0) {
|
|
FatalError("Napatech invalid "
|
|
"stream id: '%s'",
|
|
stream->val);
|
|
}
|
|
start = stream_config[instance_cnt].stream_id;
|
|
end = stream_config[instance_cnt].stream_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (stream_id = start; stream_id <= end; ++stream_id) {
|
|
/* if we get here it is configured in the .yaml file */
|
|
stream_config[instance_cnt].stream_id = stream_id;
|
|
|
|
/* Check to see if it is an active stream */
|
|
memset(&hStat, 0, sizeof(NtStatistics_t));
|
|
|
|
/* Read usage data for the chosen stream ID */
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
|
|
hStat.u.usageData_v0.streamid = (uint8_t)stream_config[instance_cnt].stream_id;
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return -1;
|
|
}
|
|
|
|
if (hStat.u.usageData_v0.data.numHostBufferUsed > 0) {
|
|
stream_config[instance_cnt].is_active = true;
|
|
}
|
|
instance_cnt++;
|
|
}
|
|
}
|
|
|
|
/* Close the statistics stream */
|
|
if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return -1;
|
|
}
|
|
|
|
if ((status = NT_InfoClose(info_stream)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return -1;
|
|
}
|
|
|
|
return instance_cnt;
|
|
}
|
|
|
|
static void *NapatechBufMonitorLoop(void *arg)
|
|
{
|
|
ThreadVars *tv = (ThreadVars *)arg;
|
|
|
|
NtInfo_t hStreamInfo;
|
|
NtStatistics_t hStat; // Stat handle.
|
|
NtInfoStream_t hInfo;
|
|
NtStatStream_t hstat_stream;
|
|
int status; // Status variable
|
|
|
|
const uint32_t alertInterval = 25;
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
uint32_t OB_fill_level[MAX_STREAMS] = { 0 };
|
|
uint32_t OB_alert_level[MAX_STREAMS] = { 0 };
|
|
uint32_t ave_OB_fill_level[MAX_STREAMS] = { 0 };
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
uint32_t HB_fill_level[MAX_STREAMS] = { 0 };
|
|
uint32_t HB_alert_level[MAX_STREAMS] = { 0 };
|
|
uint32_t ave_HB_fill_level[MAX_STREAMS] = { 0 };
|
|
|
|
/* Open the info and Statistics */
|
|
if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Read the info on all streams instantiated in the system */
|
|
hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM;
|
|
if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
NapatechStreamConfig registered_streams[MAX_STREAMS];
|
|
int num_registered = NapatechGetStreamConfig(registered_streams);
|
|
if (num_registered == -1) {
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
TmThreadsSetFlag(tv, THV_INIT_DONE | THV_RUNNING);
|
|
while (1) {
|
|
if (TmThreadsCheckFlag(tv, THV_KILL)) {
|
|
SCLogDebug("NapatechBufMonitorLoop THV_KILL detected");
|
|
break;
|
|
}
|
|
|
|
usleep(200000);
|
|
|
|
/* Read the info on all streams instantiated in the system */
|
|
hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM;
|
|
if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
char pktCntStr[4096];
|
|
memset(pktCntStr, 0, sizeof(pktCntStr));
|
|
|
|
uint32_t stream_id = 0;
|
|
uint32_t stream_cnt = 0;
|
|
uint32_t num_streams = hStreamInfo.u.stream.data.count;
|
|
|
|
for (stream_cnt = 0; stream_cnt < num_streams; ++stream_cnt) {
|
|
|
|
do {
|
|
|
|
/* Read usage data for the chosen stream ID */
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
|
|
hStat.u.usageData_v0.streamid = (uint8_t)stream_id;
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (hStat.u.usageData_v0.data.numHostBufferUsed == 0) {
|
|
++stream_id;
|
|
continue;
|
|
}
|
|
} while (hStat.u.usageData_v0.data.numHostBufferUsed == 0);
|
|
|
|
if (RegisteredStream(stream_id, num_registered, registered_streams)) {
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
ave_OB_fill_level[stream_id] = 0;
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
ave_HB_fill_level[stream_id] = 0;
|
|
|
|
for (uint32_t hb_count = 0; hb_count < hStat.u.usageData_v0.data.numHostBufferUsed;
|
|
hb_count++) {
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
OB_fill_level[hb_count] =
|
|
((100 * hStat.u.usageData_v0.data.hb[hb_count].onboardBuffering.used) /
|
|
hStat.u.usageData_v0.data.hb[hb_count].onboardBuffering.size);
|
|
|
|
if (OB_fill_level[hb_count] > 100) {
|
|
OB_fill_level[hb_count] = 100;
|
|
}
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
uint32_t bufSize =
|
|
hStat.u.usageData_v0.data.hb[hb_count].enQueuedAdapter / 1024 +
|
|
hStat.u.usageData_v0.data.hb[hb_count].deQueued / 1024 +
|
|
hStat.u.usageData_v0.data.hb[hb_count].enQueued / 1024 - HB_HIGHWATER;
|
|
|
|
HB_fill_level[hb_count] =
|
|
(uint32_t)((100 * hStat.u.usageData_v0.data.hb[hb_count].deQueued /
|
|
1024) /
|
|
bufSize);
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
ave_OB_fill_level[stream_id] += OB_fill_level[hb_count];
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
ave_HB_fill_level[stream_id] += HB_fill_level[hb_count];
|
|
}
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
ave_OB_fill_level[stream_id] /= hStat.u.usageData_v0.data.numHostBufferUsed;
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
ave_HB_fill_level[stream_id] /= hStat.u.usageData_v0.data.numHostBufferUsed;
|
|
|
|
/* Host Buffer Fill Level warnings... */
|
|
if (ave_HB_fill_level[stream_id] >= (HB_alert_level[stream_id] + alertInterval)) {
|
|
|
|
while (ave_HB_fill_level[stream_id] >=
|
|
HB_alert_level[stream_id] + alertInterval) {
|
|
HB_alert_level[stream_id] += alertInterval;
|
|
}
|
|
SCLogPerf("nt%d - Increasing Host Buffer Fill Level : %4d%%", stream_id,
|
|
ave_HB_fill_level[stream_id] - 1);
|
|
}
|
|
|
|
if (HB_alert_level[stream_id] > 0) {
|
|
if ((ave_HB_fill_level[stream_id] <=
|
|
(HB_alert_level[stream_id] - alertInterval))) {
|
|
SCLogPerf("nt%d - Decreasing Host Buffer Fill Level: %4d%%", stream_id,
|
|
ave_HB_fill_level[stream_id]);
|
|
|
|
while (ave_HB_fill_level[stream_id] <=
|
|
(HB_alert_level[stream_id] - alertInterval)) {
|
|
if ((HB_alert_level[stream_id]) > 0) {
|
|
HB_alert_level[stream_id] -= alertInterval;
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef NAPATECH_ENABLE_BYPASS
|
|
/* On Board SDRAM Fill Level warnings... */
|
|
if (ave_OB_fill_level[stream_id] >= (OB_alert_level[stream_id] + alertInterval)) {
|
|
while (ave_OB_fill_level[stream_id] >=
|
|
OB_alert_level[stream_id] + alertInterval) {
|
|
OB_alert_level[stream_id] += alertInterval;
|
|
}
|
|
SCLogPerf("nt%d - Increasing Adapter SDRAM Fill Level: %4d%%", stream_id,
|
|
ave_OB_fill_level[stream_id]);
|
|
}
|
|
|
|
if (OB_alert_level[stream_id] > 0) {
|
|
if ((ave_OB_fill_level[stream_id] <=
|
|
(OB_alert_level[stream_id] - alertInterval))) {
|
|
SCLogPerf("nt%d - Decreasing Adapter SDRAM Fill Level : %4d%%", stream_id,
|
|
ave_OB_fill_level[stream_id]);
|
|
|
|
while (ave_OB_fill_level[stream_id] <=
|
|
(OB_alert_level[stream_id] - alertInterval)) {
|
|
if ((OB_alert_level[stream_id]) > 0) {
|
|
OB_alert_level[stream_id] -= alertInterval;
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
}
|
|
++stream_id;
|
|
}
|
|
}
|
|
|
|
if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Close the statistics stream */
|
|
if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
SCLogDebug("Exiting NapatechStatsLoop");
|
|
TmThreadsSetFlag(tv, THV_RUNNING_DONE);
|
|
TmThreadWaitForFlag(tv, THV_DEINIT);
|
|
TmThreadsSetFlag(tv, THV_CLOSED);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void NapatechStartStats(void)
|
|
{
|
|
/* Creates the Statistic threads */
|
|
ThreadVars *stats_tv =
|
|
TmThreadCreate("NapatechStats", NULL, NULL, NULL, NULL, "custom", NapatechStatsLoop, 0);
|
|
|
|
if (stats_tv == NULL) {
|
|
FatalError("Error creating a thread for NapatechStats - Killing engine.");
|
|
}
|
|
|
|
if (TmThreadSpawn(stats_tv) != 0) {
|
|
FatalError("Failed to spawn thread for NapatechStats - Killing engine.");
|
|
}
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
if (bypass_supported) {
|
|
SCLogInfo("Napatech bypass functionality enabled.");
|
|
}
|
|
#endif /* NAPATECH_ENABLE_BYPASS */
|
|
|
|
ThreadVars *buf_monitor_tv = TmThreadCreate(
|
|
"NapatechBufMonitor", NULL, NULL, NULL, NULL, "custom", NapatechBufMonitorLoop, 0);
|
|
|
|
if (buf_monitor_tv == NULL) {
|
|
FatalError("Error creating a thread for NapatechBufMonitor - Killing engine.");
|
|
}
|
|
|
|
if (TmThreadSpawn(buf_monitor_tv) != 0) {
|
|
FatalError("Failed to spawn thread for NapatechBufMonitor - Killing engine.");
|
|
}
|
|
}
|
|
|
|
bool NapatechSetupNuma(uint32_t stream, uint32_t numa)
|
|
{
|
|
uint32_t status = 0;
|
|
static NtConfigStream_t hconfig;
|
|
|
|
char ntpl_cmd[64];
|
|
snprintf(ntpl_cmd, 64, "setup[numanode=%d] = streamid == %d", numa, stream);
|
|
|
|
NtNtplInfo_t ntpl_info;
|
|
|
|
if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return false;
|
|
}
|
|
|
|
if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) ==
|
|
NT_SUCCESS) {
|
|
status = ntpl_info.ntplId;
|
|
|
|
} else {
|
|
NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status);
|
|
return false;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static uint32_t NapatechSetHashmode(void)
|
|
{
|
|
uint32_t status = 0;
|
|
const char *hash_mode;
|
|
static NtConfigStream_t hconfig;
|
|
char ntpl_cmd[64];
|
|
NtNtplInfo_t ntpl_info;
|
|
|
|
uint32_t filter_id = 0;
|
|
|
|
/* Get the hashmode from the conf file. */
|
|
ConfGet("napatech.hashmode", &hash_mode);
|
|
|
|
snprintf(ntpl_cmd, 64, "hashmode = %s", hash_mode);
|
|
|
|
/* Issue the NTPL command */
|
|
if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
return false;
|
|
}
|
|
|
|
if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) ==
|
|
NT_SUCCESS) {
|
|
filter_id = ntpl_info.ntplId;
|
|
SCLogConfig("Napatech hashmode: %s ID: %d", hash_mode, status);
|
|
} else {
|
|
NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status);
|
|
status = 0;
|
|
}
|
|
|
|
return filter_id;
|
|
}
|
|
|
|
static uint32_t GetStreamNUMAs(uint32_t stream_id, int stream_numas[])
|
|
{
|
|
NtStatistics_t hStat; // Stat handle.
|
|
NtStatStream_t hstat_stream;
|
|
int status; // Status variable
|
|
|
|
for (int i = 0; i < MAX_HOSTBUFFERS; ++i)
|
|
stream_numas[i] = -1;
|
|
|
|
if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
char pktCntStr[4096];
|
|
memset(pktCntStr, 0, sizeof(pktCntStr));
|
|
|
|
/* Read usage data for the chosen stream ID */
|
|
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
|
|
hStat.u.usageData_v0.streamid = (uint8_t)stream_id;
|
|
|
|
if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
for (uint32_t hb_id = 0; hb_id < hStat.u.usageData_v0.data.numHostBufferUsed; ++hb_id) {
|
|
stream_numas[hb_id] = hStat.u.usageData_v0.data.hb[hb_id].numaNode;
|
|
}
|
|
|
|
return hStat.u.usageData_v0.data.numHostBufferUsed;
|
|
}
|
|
|
|
static int NapatechSetFilter(NtConfigStream_t hconfig, char *ntpl_cmd)
|
|
{
|
|
int status = 0;
|
|
int local_filter_id = 0;
|
|
|
|
NtNtplInfo_t ntpl_info;
|
|
if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) ==
|
|
NT_SUCCESS) {
|
|
SCLogConfig(
|
|
"NTPL filter assignment \"%s\" returned filter id %4d", ntpl_cmd, local_filter_id);
|
|
} else {
|
|
NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return local_filter_id;
|
|
}
|
|
|
|
uint32_t NapatechDeleteFilters(void)
|
|
{
|
|
uint32_t status = 0;
|
|
static NtConfigStream_t hconfig;
|
|
char ntpl_cmd[64];
|
|
NtNtplInfo_t ntpl_info;
|
|
|
|
if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
snprintf(ntpl_cmd, 64, "delete = all");
|
|
if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) ==
|
|
NT_SUCCESS) {
|
|
status = ntpl_info.ntplId;
|
|
} else {
|
|
NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status);
|
|
status = 0;
|
|
}
|
|
|
|
NT_ConfigClose(hconfig);
|
|
|
|
return status;
|
|
}
|
|
|
|
uint32_t NapatechSetupTraffic(uint32_t first_stream, uint32_t last_stream)
|
|
{
|
|
#define PORTS_SPEC_SIZE 64
|
|
|
|
struct ports_spec_s {
|
|
uint8_t first[MAX_PORTS];
|
|
uint8_t second[MAX_PORTS];
|
|
bool all;
|
|
char str[PORTS_SPEC_SIZE];
|
|
} ports_spec;
|
|
|
|
ports_spec.all = false;
|
|
|
|
ConfNode *ntports;
|
|
int iteration = 0;
|
|
int status = 0;
|
|
NtConfigStream_t hconfig;
|
|
char ntpl_cmd[512];
|
|
int is_inline = 0;
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
int is_span_port[MAX_PORTS] = { 0 };
|
|
#endif
|
|
|
|
char span_ports[128];
|
|
memset(span_ports, 0, sizeof(span_ports));
|
|
|
|
if (ConfGetBool("napatech.inline", &is_inline) == 0) {
|
|
is_inline = 0;
|
|
}
|
|
|
|
NapatechSetHashmode();
|
|
|
|
if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) {
|
|
NAPATECH_ERROR(status);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (first_stream == last_stream) {
|
|
snprintf(
|
|
ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=inactive] = StreamId == %d", first_stream);
|
|
} else {
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=inactive] = StreamId == (%d..%d)",
|
|
first_stream, last_stream);
|
|
}
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
if (NapatechUseHWBypass()) {
|
|
SCLogInfo("Napatech Hardware Bypass enabled.");
|
|
}
|
|
#else
|
|
if (NapatechUseHWBypass()) {
|
|
SCLogInfo("Napatech Hardware Bypass requested in conf but is not available.");
|
|
exit(EXIT_FAILURE);
|
|
} else {
|
|
SCLogInfo("Napatech Hardware Bypass disabled.");
|
|
}
|
|
#endif
|
|
|
|
if (is_inline) {
|
|
SCLogInfo("Napatech configured for inline mode.");
|
|
} else {
|
|
|
|
SCLogInfo("Napatech configured for passive (non-inline) mode.");
|
|
}
|
|
|
|
/* When not using the default streams we need to parse
|
|
* the array of streams from the conf
|
|
*/
|
|
if ((ntports = ConfGetNode("napatech.ports")) == NULL) {
|
|
FatalError("Failed retrieving napatech.ports from Conf");
|
|
}
|
|
|
|
/* Loop through all ports in the array */
|
|
ConfNode *port;
|
|
enum CONFIG_SPECIFIER stream_spec = CONFIG_SPECIFIER_UNDEFINED;
|
|
|
|
if (NapatechUseHWBypass()) {
|
|
SCLogInfo("Listening on the following Napatech ports:");
|
|
}
|
|
/* Build the NTPL command using values in the config file. */
|
|
TAILQ_FOREACH (port, &ntports->head, next) {
|
|
if (port == NULL) {
|
|
FatalError("Couldn't Parse Port Configuration");
|
|
}
|
|
|
|
if (NapatechUseHWBypass()) {
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
if (strchr(port->val, '-')) {
|
|
stream_spec = CONFIG_SPECIFIER_RANGE;
|
|
|
|
if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) {
|
|
FatalError("Invalid value '%s' in napatech.ports specification in conf file.",
|
|
port->val);
|
|
}
|
|
|
|
if (ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0,
|
|
strchr(port->val, '-') + 1) == -1) {
|
|
FatalError("Invalid value '%s' in napatech.ports specification in conf file.",
|
|
port->val);
|
|
}
|
|
|
|
if (ports_spec.first[iteration] == ports_spec.second[iteration]) {
|
|
if (is_inline) {
|
|
FatalError(
|
|
"Error with napatech.ports in conf file. When running in inline "
|
|
"mode the two ports specifying a segment must be different.");
|
|
} else {
|
|
/* SPAN port configuration */
|
|
is_span_port[ports_spec.first[iteration]] = 1;
|
|
|
|
if (strlen(span_ports) == 0) {
|
|
snprintf(span_ports, sizeof(span_ports), "%d",
|
|
ports_spec.first[iteration]);
|
|
} else {
|
|
char temp[16];
|
|
snprintf(temp, sizeof(temp), ",%d", ports_spec.first[iteration]);
|
|
strlcat(span_ports, temp, sizeof(span_ports));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NapatechGetAdapter(ports_spec.first[iteration]) !=
|
|
NapatechGetAdapter(ports_spec.first[iteration])) {
|
|
SCLogError("Invalid napatech.ports specification in conf file.");
|
|
SCLogError("Two ports on a segment must reside on the same adapter. port %d "
|
|
"is on adapter %d, port %d is on adapter %d.",
|
|
ports_spec.first[iteration],
|
|
NapatechGetAdapter(ports_spec.first[iteration]),
|
|
ports_spec.second[iteration],
|
|
NapatechGetAdapter(ports_spec.second[iteration]));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
NapatechSetPortmap(ports_spec.first[iteration], ports_spec.second[iteration]);
|
|
if (ports_spec.first[iteration] == ports_spec.second[iteration]) {
|
|
SCLogInfo(" span_port: %d", ports_spec.first[iteration]);
|
|
} else {
|
|
SCLogInfo(" %s: %d - %d", is_inline ? "inline_ports" : "tap_ports",
|
|
ports_spec.first[iteration], ports_spec.second[iteration]);
|
|
}
|
|
|
|
if (iteration == 0) {
|
|
if (ports_spec.first[iteration] == ports_spec.second[iteration]) {
|
|
snprintf(ports_spec.str, sizeof(ports_spec.str), "%d",
|
|
ports_spec.first[iteration]);
|
|
} else {
|
|
snprintf(ports_spec.str, sizeof(ports_spec.str), "%d,%d",
|
|
ports_spec.first[iteration], ports_spec.second[iteration]);
|
|
}
|
|
} else {
|
|
char temp[16];
|
|
if (ports_spec.first[iteration] == ports_spec.second[iteration]) {
|
|
snprintf(temp, sizeof(temp), ",%d", ports_spec.first[iteration]);
|
|
} else {
|
|
snprintf(temp, sizeof(temp), ",%d,%d", ports_spec.first[iteration],
|
|
ports_spec.second[iteration]);
|
|
}
|
|
strlcat(ports_spec.str, temp, sizeof(ports_spec.str));
|
|
}
|
|
} else {
|
|
FatalError("When using hardware flow bypass ports must be specified as segments. "
|
|
"E.g. ports: [0-1, 0-2]");
|
|
}
|
|
#endif
|
|
} else { // !NapatechUseHWBypass()
|
|
if (strncmp(port->val, "all", 3) == 0) {
|
|
/* check that the sting in the config file is correctly specified */
|
|
if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) {
|
|
FatalError("Only one Napatech port specifier type is allowed.");
|
|
}
|
|
stream_spec = CONFIG_SPECIFIER_RANGE;
|
|
|
|
ports_spec.all = true;
|
|
snprintf(ports_spec.str, sizeof(ports_spec.str), "all");
|
|
} else if (strchr(port->val, '-')) {
|
|
/* check that the sting in the config file is correctly specified */
|
|
if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) {
|
|
FatalError("Only one Napatech port specifier is allowed when hardware bypass "
|
|
"is disabled. (E.g. ports: [0-4], NOT ports: [0-1,2-3])");
|
|
}
|
|
stream_spec = CONFIG_SPECIFIER_RANGE;
|
|
|
|
if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) {
|
|
FatalError("Invalid value '%s' in napatech.ports specification in conf file.",
|
|
port->val);
|
|
}
|
|
|
|
if (ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0,
|
|
strchr(port->val, '-') + 1) == -1) {
|
|
FatalError("Invalid value '%s' in napatech.ports specification in conf file.",
|
|
port->val);
|
|
}
|
|
|
|
snprintf(ports_spec.str, sizeof(ports_spec.str), "(%d..%d)",
|
|
ports_spec.first[iteration], ports_spec.second[iteration]);
|
|
} else {
|
|
/* check that the sting in the config file is correctly specified */
|
|
if (stream_spec == CONFIG_SPECIFIER_RANGE) {
|
|
FatalError("Napatech port range specifiers cannot be combined with individual "
|
|
"stream specifiers.");
|
|
}
|
|
stream_spec = CONFIG_SPECIFIER_INDIVIDUAL;
|
|
|
|
if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) {
|
|
FatalError("Invalid value '%s' in napatech.ports specification in conf file.",
|
|
port->val);
|
|
}
|
|
|
|
/* Determine the ports to use on the NTPL assign statement*/
|
|
if (iteration == 0) {
|
|
snprintf(ports_spec.str, sizeof(ports_spec.str), "%s", port->val);
|
|
} else {
|
|
strlcat(ports_spec.str, ",", sizeof(ports_spec.str));
|
|
strlcat(ports_spec.str, port->val, sizeof(ports_spec.str));
|
|
}
|
|
}
|
|
} // if !NapatechUseHWBypass()
|
|
++iteration;
|
|
} /* TAILQ_FOREACH */
|
|
|
|
#ifdef NAPATECH_ENABLE_BYPASS
|
|
if (bypass_supported) {
|
|
if (is_inline) {
|
|
char inline_setup_cmd[512];
|
|
if (first_stream == last_stream) {
|
|
snprintf(inline_setup_cmd, sizeof(ntpl_cmd),
|
|
"Setup[TxDescriptor=Dyn;TxPorts=%s;RxCRC=False;TxPortPos=112;UseWL=True] = "
|
|
"StreamId == %d",
|
|
ports_spec.str, first_stream);
|
|
} else {
|
|
snprintf(inline_setup_cmd, sizeof(ntpl_cmd),
|
|
"Setup[TxDescriptor=Dyn;TxPorts=%s;RxCRC=False;TxPortPos=112;UseWL=True] = "
|
|
"StreamId == (%d..%d)",
|
|
ports_spec.str, first_stream, last_stream);
|
|
}
|
|
NapatechSetFilter(hconfig, inline_setup_cmd);
|
|
}
|
|
/* Build the NTPL command */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=3;streamid=(%d..%d);colormask=0x10000000;"
|
|
"Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1="
|
|
"Layer4Header[0]]= %s%s",
|
|
first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=2;streamid=(%d..%d);colormask=0x11000000;"
|
|
"Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1="
|
|
"Layer4Header[0]"
|
|
"]= %s%s and (Layer3Protocol==IPV4)",
|
|
first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=2;streamid=(%d..%d);colormask=0x14000000;"
|
|
"Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1="
|
|
"Layer4Header[0]]= %s%s and (Layer3Protocol==IPV6)",
|
|
first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=2;streamid=(%d..%d);colormask=0x10100000;"
|
|
"Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1="
|
|
"Layer4Header[0]]= %s%s and (Layer4Protocol==TCP)",
|
|
first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=2;streamid=(%d..%d);colormask=0x10200000;"
|
|
"Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1="
|
|
"Layer4Header[0]"
|
|
"]= %s%s and (Layer4Protocol==UDP)",
|
|
first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
if (strlen(span_ports) > 0) {
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=2;streamid=(%d..%d);colormask=0x00001000;"
|
|
"Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1="
|
|
"Layer4Header[0]"
|
|
"]= port==%s",
|
|
first_stream, last_stream, span_ports);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={sw_32_32,sw_16_16}",
|
|
NAPATECH_KEYTYPE_IPV4);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER]=(Layer3Header[12]/32/"
|
|
"32,Layer4Header[0]/16/16)",
|
|
NAPATECH_KEYTYPE_IPV4, NAPATECH_KEYTYPE_IPV4);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={32,32,16,16}",
|
|
NAPATECH_KEYTYPE_IPV4_SPAN);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER;keysort=sorted]=("
|
|
"Layer3Header[12]/32,Layer3Header[16]/32,Layer4Header[0]/16,Layer4Header[2]/16)",
|
|
NAPATECH_KEYTYPE_IPV4_SPAN, NAPATECH_KEYTYPE_IPV4_SPAN);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
/* IPv6 5tuple for inline and tap ports */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={sw_128_128,sw_16_16}",
|
|
NAPATECH_KEYTYPE_IPV6);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER]=(Layer3Header[8]/128/"
|
|
"128,Layer4Header[0]/16/16)",
|
|
NAPATECH_KEYTYPE_IPV6, NAPATECH_KEYTYPE_IPV6);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
/* IPv6 5tuple for SPAN Ports */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={128,128,16,16}",
|
|
NAPATECH_KEYTYPE_IPV6_SPAN);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER;keysort=sorted]=("
|
|
"Layer3Header[8]/128,Layer3Header[24]/128,Layer4Header[0]/16,Layer4Header[2]/16)",
|
|
NAPATECH_KEYTYPE_IPV6_SPAN, NAPATECH_KEYTYPE_IPV6_SPAN);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
int pair;
|
|
char ports_ntpl_a[64];
|
|
char ports_ntpl_b[64];
|
|
memset(ports_ntpl_a, 0, sizeof(ports_ntpl_a));
|
|
memset(ports_ntpl_b, 0, sizeof(ports_ntpl_b));
|
|
|
|
for (pair = 0; pair < iteration; ++pair) {
|
|
char port_str[8];
|
|
|
|
if (!is_span_port[ports_spec.first[pair]]) {
|
|
snprintf(port_str, sizeof(port_str), "%s%u ", strlen(ports_ntpl_a) == 0 ? "" : ",",
|
|
ports_spec.first[pair]);
|
|
strlcat(ports_ntpl_a, port_str, sizeof(ports_ntpl_a));
|
|
|
|
snprintf(port_str, sizeof(port_str), "%s%u ", strlen(ports_ntpl_b) == 0 ? "" : ",",
|
|
ports_spec.second[pair]);
|
|
strlcat(ports_ntpl_b, port_str, sizeof(ports_ntpl_b));
|
|
}
|
|
}
|
|
|
|
if (strlen(ports_ntpl_a) > 0) {
|
|
/* This is the assign for dropping upstream traffic */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port "
|
|
"== %s)and(Key(KDEF%u,KeyID=%u)==%u)",
|
|
ports_ntpl_a, NAPATECH_KEYTYPE_IPV4, NAPATECH_KEYTYPE_IPV4,
|
|
NAPATECH_FLOWTYPE_DROP);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
|
|
if (strlen(ports_ntpl_b) > 0) {
|
|
/* This is the assign for dropping downstream traffic */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port "
|
|
"== %s)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)",
|
|
ports_ntpl_b, // ports_spec.str,
|
|
NAPATECH_KEYTYPE_IPV4, NAPATECH_KEYTYPE_IPV4, NAPATECH_FLOWTYPE_DROP);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
|
|
if (strlen(span_ports) > 0) {
|
|
/* This is the assign for dropping SPAN Port traffic */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port "
|
|
"== %s)and(Key(KDEF%u,KeyID=%u)==%u)",
|
|
span_ports, NAPATECH_KEYTYPE_IPV4_SPAN, NAPATECH_KEYTYPE_IPV4_SPAN,
|
|
NAPATECH_FLOWTYPE_DROP);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
|
|
if (is_inline) {
|
|
for (pair = 0; pair < iteration; ++pair) {
|
|
/* This is the assignment for forwarding traffic */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x2]=("
|
|
"Layer3Protocol==IPV4)and(port == %d)and(Key(KDEF%u,KeyID=%u)==%u)",
|
|
ports_spec.second[pair], ports_spec.first[pair], NAPATECH_KEYTYPE_IPV4,
|
|
NAPATECH_KEYTYPE_IPV4, NAPATECH_FLOWTYPE_PASS);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x2]=("
|
|
"Layer3Protocol==IPV4)and(port == "
|
|
"%d)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)",
|
|
ports_spec.first[pair], ports_spec.second[pair], NAPATECH_KEYTYPE_IPV4,
|
|
NAPATECH_KEYTYPE_IPV4, NAPATECH_FLOWTYPE_PASS);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
}
|
|
|
|
if (strlen(ports_ntpl_a) > 0) {
|
|
/* This is the assign for dropping upstream traffic */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port "
|
|
"== %s)and(Key(KDEF%u,KeyID=%u)==%u)",
|
|
ports_ntpl_a, NAPATECH_KEYTYPE_IPV6, NAPATECH_KEYTYPE_IPV6,
|
|
NAPATECH_FLOWTYPE_DROP);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
|
|
if (strlen(ports_ntpl_b) > 0) {
|
|
/* This is the assign for dropping downstream traffic */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port "
|
|
"== %s)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)",
|
|
ports_ntpl_b, // ports_spec.str,
|
|
NAPATECH_KEYTYPE_IPV6, NAPATECH_KEYTYPE_IPV6, NAPATECH_FLOWTYPE_DROP);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
|
|
if (strlen(span_ports) > 0) {
|
|
/* This is the assign for dropping SPAN Port traffic */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port "
|
|
"== %s)and(Key(KDEF%u,KeyID=%u)==%u)",
|
|
span_ports, NAPATECH_KEYTYPE_IPV6_SPAN, NAPATECH_KEYTYPE_IPV6_SPAN,
|
|
NAPATECH_FLOWTYPE_DROP);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
|
|
if (is_inline) {
|
|
for (pair = 0; pair < iteration; ++pair) {
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x4]=("
|
|
"Layer3Protocol==IPV6)and(port==%d)and(Key(KDEF%u,KeyID=%u)==%u)",
|
|
ports_spec.second[pair], ports_spec.first[pair], NAPATECH_KEYTYPE_IPV6,
|
|
NAPATECH_KEYTYPE_IPV6, NAPATECH_FLOWTYPE_PASS);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd),
|
|
"assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x4]=("
|
|
"Layer3Protocol==IPV6)and(port==%d)and(Key(KDEF%u,KeyID=%u,fieldaction="
|
|
"swap)==%u)",
|
|
ports_spec.first[pair], ports_spec.second[pair], NAPATECH_KEYTYPE_IPV6,
|
|
NAPATECH_KEYTYPE_IPV6, NAPATECH_FLOWTYPE_PASS);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
}
|
|
} else {
|
|
if (is_inline) {
|
|
FatalError("Napatech Inline operation not supported by this FPGA version.");
|
|
}
|
|
|
|
if (NapatechIsAutoConfigEnabled()) {
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "assign[streamid=(%d..%d);colormask=0x0] = %s%s",
|
|
first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
}
|
|
}
|
|
|
|
#else /* NAPATECH_ENABLE_BYPASS */
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "assign[streamid=(%d..%d)] = %s%s", first_stream,
|
|
last_stream, ports_spec.all ? "" : "port==", ports_spec.str);
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
#endif /* !NAPATECH_ENABLE_BYPASS */
|
|
|
|
SCLogConfig("Host-buffer NUMA assignments: ");
|
|
int numa_nodes[MAX_HOSTBUFFERS];
|
|
uint32_t stream_id;
|
|
for (stream_id = first_stream; stream_id < last_stream; ++stream_id) {
|
|
char temp1[256];
|
|
char temp2[256];
|
|
|
|
uint32_t num_host_buffers = GetStreamNUMAs(stream_id, numa_nodes);
|
|
|
|
snprintf(temp1, 256, " stream %d: ", stream_id);
|
|
|
|
for (uint32_t hb_id = 0; hb_id < num_host_buffers; ++hb_id) {
|
|
snprintf(temp2, 256, "%d ", numa_nodes[hb_id]);
|
|
strlcat(temp1, temp2, sizeof(temp1));
|
|
}
|
|
|
|
SCLogConfig("%s", temp1);
|
|
}
|
|
|
|
if (first_stream == last_stream) {
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=active] = StreamId == %d", first_stream);
|
|
} else {
|
|
snprintf(ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=active] = StreamId == (%d..%d)",
|
|
first_stream, last_stream);
|
|
}
|
|
NapatechSetFilter(hconfig, ntpl_cmd);
|
|
|
|
NT_ConfigClose(hconfig);
|
|
|
|
return status;
|
|
}
|