/**
* \file
*
-- * \author nPulse Technologies, LLC.
-- * \author Matt Keeler <mk@npulsetech.com>
+ - * \author nPulse Technologies, LLC.
+ - * \author Matt Keeler <mk@npulsetech.com>
* *
* Support for NAPATECH adapter with the 3GD Driver/API.
* Requires libntapi from Napatech A/S.
*
*/
-
#include "suricata-common.h"
#include "suricata.h"
#include "threadvars.h"
#ifndef HAVE_NAPATECH
-TmEcode NoNapatechSupportExit(ThreadVars *, const void *, void **);
+TmEcode NoNapatechSupportExit(ThreadVars*, const void*, void**);
void TmModuleNapatechStreamRegister(void)
{
{
SCLogError(SC_ERR_NAPATECH_NOSUPPORT,
"Error creating thread %s: you do not have support for Napatech adapter "
- "enabled please recompile with --enable-napatech", tv->name);
+ "enabled please recompile with --enable-napatech",
+ tv->name);
exit(EXIT_FAILURE);
}
#else /* Implied we do have NAPATECH support */
+
#include <numa.h>
#include <nt.h>
-#define MAX_STREAMS 256
-
extern int max_pending_packets;
-typedef struct NapatechThreadVars_ {
+typedef struct NapatechThreadVars_
+{
ThreadVars *tv;
NtNetStreamRx_t rx_stream;
uint16_t stream_id;
TmSlot *slot;
} NapatechThreadVars;
+#ifdef NAPATECH_ENABLE_BYPASS
+static int NapatechBypassCallback(Packet *p);
+#endif
TmEcode NapatechStreamThreadInit(ThreadVars *, const void *, void **);
void NapatechStreamThreadExitStats(ThreadVars *, void *);
-TmEcode NapatechPacketLoopZC(ThreadVars *tv, void *data, void *slot);
+TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot);
TmEcode NapatechDecodeThreadInit(ThreadVars *, const void *, void **);
TmEcode NapatechDecodeThreadDeinit(ThreadVars *tv, void *data);
SC_ATOMIC_DECLARE(uint16_t, numa2_count);
SC_ATOMIC_DECLARE(uint16_t, numa3_count);
+SC_ATOMIC_DECLARE(uint64_t, flow_callback_cnt);
+SC_ATOMIC_DECLARE(uint64_t, flow_callback_handled_pkts);
+SC_ATOMIC_DECLARE(uint64_t, flow_callback_udp_pkts);
+SC_ATOMIC_DECLARE(uint64_t, flow_callback_tcp_pkts);
+SC_ATOMIC_DECLARE(uint64_t, flow_callback_unhandled_pkts);
+
/**
* \brief Register the Napatech receiver (reader) module.
*/
tmm_modules[TMM_RECEIVENAPATECH].name = "NapatechStream";
tmm_modules[TMM_RECEIVENAPATECH].ThreadInit = NapatechStreamThreadInit;
tmm_modules[TMM_RECEIVENAPATECH].Func = NULL;
- tmm_modules[TMM_RECEIVENAPATECH].PktAcqLoop = NapatechPacketLoopZC;
+ tmm_modules[TMM_RECEIVENAPATECH].PktAcqLoop = NapatechPacketLoop;
tmm_modules[TMM_RECEIVENAPATECH].PktAcqBreakLoop = NULL;
tmm_modules[TMM_RECEIVENAPATECH].ThreadExitPrintStats = NapatechStreamThreadExitStats;
tmm_modules[TMM_RECEIVENAPATECH].ThreadDeinit = NapatechStreamThreadDeinit;
SC_ATOMIC_INIT(numa1_count);
SC_ATOMIC_INIT(numa2_count);
SC_ATOMIC_INIT(numa3_count);
+
+ SC_ATOMIC_INIT(flow_callback_cnt);
+ SC_ATOMIC_INIT(flow_callback_handled_pkts);
+ SC_ATOMIC_INIT(flow_callback_udp_pkts);
+ SC_ATOMIC_INIT(flow_callback_tcp_pkts);
+ SC_ATOMIC_INIT(flow_callback_unhandled_pkts);
}
/**
tmm_modules[TMM_DECODENAPATECH].flags = TM_FLAG_DECODE_TM;
}
+#ifdef NAPATECH_ENABLE_BYPASS
+/**
+ * \brief template of IPv4 header
+ */
+struct ipv4_hdr
+{
+ uint8_t version_ihl; /**< version and header length */
+ uint8_t type_of_service; /**< type of service */
+ uint16_t total_length; /**< length of packet */
+ uint16_t packet_id; /**< packet ID */
+ uint16_t fragment_offset; /**< fragmentation offset */
+ uint8_t time_to_live; /**< time to live */
+ uint8_t next_proto_id; /**< protocol ID */
+ uint16_t hdr_checksum; /**< header checksum */
+ uint32_t src_addr; /**< source address */
+ uint32_t dst_addr; /**< destination address */
+} __attribute__ ((__packed__));
+
+/**
+ * \brief template of IPv6 header
+ */
+struct ipv6_hdr
+{
+ uint32_t vtc_flow; /**< IP version, traffic class & flow label. */
+ uint16_t payload_len; /**< IP packet length - includes sizeof(ip_header). */
+ uint8_t proto; /**< Protocol, next header. */
+ uint8_t hop_limits; /**< Hop limits. */
+ uint8_t src_addr[16]; /**< IP address of source host. */
+ uint8_t dst_addr[16]; /**< IP address of destination host(s). */
+} __attribute__ ((__packed__));
+
+/**
+ * \brief template of UDP header
+ */
+struct udp_hdr
+{
+ uint16_t src_port; /**< UDP source port. */
+ uint16_t dst_port; /**< UDP destination port. */
+ uint16_t dgram_len; /**< UDP datagram length */
+ uint16_t dgram_cksum; /**< UDP datagram checksum */
+} __attribute__ ((__packed__));
+
+/**
+ * \brief template of TCP header
+ */
+struct tcp_hdr
+{
+ uint16_t src_port; /**< TCP source port. */
+ uint16_t dst_port; /**< TCP destination port. */
+ uint32_t sent_seq; /**< TX data sequence number. */
+ uint32_t recv_ack; /**< RX data acknowledgement sequence number. */
+ uint8_t data_off; /**< Data offset. */
+ uint8_t tcp_flags; /**< TCP flags */
+ uint16_t rx_win; /**< RX flow control window. */
+ uint16_t cksum; /**< TCP checksum. */
+ uint16_t tcp_urp; /**< TCP urgent pointer, if any. */
+} __attribute__ ((__packed__));
+
+
+/* The hardware will assign a "color" value indicating what filters are matched
+ * by a given packet. These constants indicate what bits are set in the color
+ * field for different protocols
+ *
+ */
+#define RTE_PTYPE_L2_ETHER 0x10000000
+#define RTE_PTYPE_L3_IPV4 0x01000000
+#define RTE_PTYPE_L3_IPV6 0x04000000
+#define RTE_PTYPE_L4_TCP 0x00100000
+#define RTE_PTYPE_L4_UDP 0x00200000
+
+/* These masks are used to extract layer 3 and layer 4 protocol
+ * values from the color field in the packet descriptor.
+ */
+#define RTE_PTYPE_L3_MASK 0x0f000000
+#define RTE_PTYPE_L4_MASK 0x00f00000
+
+#define COLOR_IS_SPAN 0x00001000
+
+static int inline_port_map[MAX_PORTS] = { -1 };
+
+/**
+ * \brief Binds two ports together for inline operation.
+ *
+ * Get the ID of an adapter on which a given port resides.
+ *
+ * \param port one of the ports in a pairing.
+ * \param peer the other port in a pairing.
+ * \return ID of the adapter.
+ *
+ */
+int NapatechSetPortmap(int port, int peer)
+{
+ if ((inline_port_map[port] == -1) && (inline_port_map[peer] == -1)) {
+ inline_port_map[port] = peer;
+ inline_port_map[peer] = port;
+ } else {
+ SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
+ "Port pairing is already configured.");
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * \brief Returns the ID of the adapter
+ *
+ * Get the ID of an adapter on which a given port resides.
+ *
+ * \param port for which adapter ID is requested.
+ * \return ID of the adapter.
+ *
+ */
+int NapatechGetAdapter(uint8_t port)
+{
+ static int port_adapter_map[MAX_PORTS] = { -1 };
+ int status;
+ NtInfo_t h_info; /* Info handle */
+ NtInfoStream_t h_info_stream; /* Info stream handle */
+
+ if (unlikely(port_adapter_map[port] == -1)) {
+ if ((status = NT_InfoOpen(&h_info_stream, "ExampleInfo")) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_OPEN_FAILED, status);
+ return -1;
+ }
+ /* Read the system info */
+ h_info.cmd = NT_INFO_CMD_READ_PORT_V9;
+ h_info.u.port_v9.portNo = (uint8_t) port;
+ if ((status = NT_InfoRead(h_info_stream, &h_info)) != NT_SUCCESS) {
+ /* Get the status code as text */
+ NAPATECH_ERROR(SC_ERR_NAPATECH_OPEN_FAILED, status);
+ NT_InfoClose(h_info_stream);
+ return -1;
+ }
+ port_adapter_map[port] = h_info.u.port_v9.data.adapterNo;
+ }
+ return port_adapter_map[port];
+}
+
+/**
+ * \brief IPv4 4-tuple convenience structure
+ */
+struct IPv4Tuple4
+{
+ uint32_t sa; /*!< Source address */
+ uint32_t da; /*!< Destination address */
+ uint16_t sp; /*!< Source port */
+ uint16_t dp; /*!< Destination port */
+};
+
+/**
+ * \brief IPv6 4-tuple convenience structure
+ */
+struct IPv6Tuple4
+{
+ uint8_t sa[16]; /*!< Source address */
+ uint8_t da[16]; /*!< Destination address */
+ uint16_t sp; /*!< Source port */
+ uint16_t dp; /*!< Destination port */
+};
+
+
+/**
+ * \brief Compares the byte order value of two IPv6 addresses.
+ *
+ *
+ * \param addr_a The first address to compare
+ * \param addr_b The second adress to compare
+ *
+ * \return -1 if addr_a < addr_b
+ * 1 if addr_a > addr_b
+ * 0 if addr_a == addr_b
+ */
+static int CompareIPv6Addr(uint8_t addr_a[16], uint8_t addr_b[16]) {
+ uint16_t pos;
+ for (pos = 0; pos < 16; ++pos) {
+ if (addr_a[pos] < addr_b[pos]) {
+ return -1;
+ } else if (addr_a[pos] > addr_b[pos]) {
+ return 1;
+ } /* else they are equal - check next position*/
+ }
+
+ /* if we get here the addresses are equal */
+ return 0;
+}
+
+/**
+ * \brief Callback function to process Bypass events on Napatech Adapter.
+ *
+ * Callback function that sets up the Flow tables on the Napatech card
+ * so that subsequent packets from this flow are bypassed on the hardware.
+ *
+ * \param p packet containing information about the flow to be bypassed
+ * \param is_inline indicates if Suricata is being run in inline mode.
+ *
+ * \return Error code indicating success (1) or failure (0).
+ *
+ */
+static int ProgramFlow(Packet *p, int is_inline)
+{
+ int status;
+ NtFlow_t flow_match;
+ memset(&flow_match, 0, sizeof(flow_match));
+
+ NapatechPacketVars *ntpv = &(p->ntpv);
+
+ int adapter = NapatechGetAdapter(ntpv->dyn3->rxPort);
+
+ NtFlowStream_t *phFlowStream = NapatechGetFlowStreamPtr(adapter);
+
+
+ /*
+ * The hardware decoder will "color" the packets according to the protocols
+ * in the packet and the port the packet arrived on. packet_type gets
+ * these bits and we mask out layer3, layer4, and is_span to determine
+ * the protocols and if the packet is coming in from a SPAN port.
+ */
+ uint32_t packet_type = ((ntpv->dyn3->color_hi << 14) & 0xFFFFC000) | ntpv->dyn3->color_lo;
+ uint8_t *packet = (uint8_t *) ntpv->dyn3 + ntpv->dyn3->descrLength;
+
+ uint32_t layer3 = packet_type & RTE_PTYPE_L3_MASK;
+ uint32_t layer4 = packet_type & RTE_PTYPE_L4_MASK;
+ uint32_t is_span = packet_type & COLOR_IS_SPAN;
+
+ /*
+ * When we're programming the flows to arrive on a span port,
+ * where upstream and downstream packets arrive on the same port,
+ * the hardware is configured to swap the source and dest
+ * fields if the src addr > dest addr. We need to program the
+ * flow tables to match. We'll compare addresses and set
+ * do_swap accordingly.
+ */
+
+ uint32_t do_swap = 0;
+
+ SC_ATOMIC_ADD(flow_callback_cnt, 1);
+
+ /* Only bypass TCP and UDP */
+ if (PKT_IS_TCP(p)) {
+ SC_ATOMIC_ADD(flow_callback_tcp_pkts, 1);
+ } else if PKT_IS_UDP(p) {
+ SC_ATOMIC_ADD(flow_callback_udp_pkts, 1);
+ } else {
+ SC_ATOMIC_ADD(flow_callback_unhandled_pkts, 1);
+ }
+
+ struct IPv4Tuple4 v4Tuple;
+ struct IPv6Tuple4 v6Tuple;
+ struct ipv4_hdr *pIPv4_hdr = NULL;
+ struct ipv6_hdr *pIPv6_hdr = NULL;
+
+ switch (layer3) {
+ case RTE_PTYPE_L3_IPV4:
+ {
+ pIPv4_hdr = (struct ipv4_hdr *) (packet + ntpv->dyn3->offset0);
+
+ if (!is_span) {
+ v4Tuple.sa = pIPv4_hdr->src_addr;
+ v4Tuple.da = pIPv4_hdr->dst_addr;
+ } else {
+ do_swap = (pIPv4_hdr->src_addr > pIPv4_hdr->dst_addr);
+ if (!do_swap) {
+ /* already in order */
+ v4Tuple.sa = pIPv4_hdr->src_addr;
+ v4Tuple.da = pIPv4_hdr->dst_addr;
+ } else { /* swap */
+ v4Tuple.sa = pIPv4_hdr->dst_addr;
+ v4Tuple.da = pIPv4_hdr->src_addr;
+ }
+ }
+ break;
+ }
+ case RTE_PTYPE_L3_IPV6:
+ {
+ pIPv6_hdr = (struct ipv6_hdr *) (packet + ntpv->dyn3->offset0);
+ do_swap = (CompareIPv6Addr(pIPv6_hdr->src_addr, pIPv6_hdr->dst_addr) > 0);
+
+ if (!is_span) {
+ memcpy(&(v6Tuple.sa), pIPv6_hdr->src_addr, 16);
+ memcpy(&(v6Tuple.da), pIPv6_hdr->dst_addr, 16);
+ } else {
+ /* sort src/dest address before programming */
+ if (!do_swap) {
+ /* already in order */
+ memcpy(&(v6Tuple.sa), pIPv6_hdr->src_addr, 16);
+ memcpy(&(v6Tuple.da), pIPv6_hdr->dst_addr, 16);
+ } else { /* swap the addresses */
+ memcpy(&(v6Tuple.sa), pIPv6_hdr->dst_addr, 16);
+ memcpy(&(v6Tuple.da), pIPv6_hdr->src_addr, 16);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ return 0;
+ }
+ }
+
+ switch (layer4) {
+ case RTE_PTYPE_L4_TCP:
+ {
+ struct tcp_hdr *tcp_hdr = (struct tcp_hdr *) (packet + ntpv->dyn3->offset1);
+ if (layer3 == RTE_PTYPE_L3_IPV4) {
+ if (!is_span) {
+ v4Tuple.dp = tcp_hdr->dst_port;
+ v4Tuple.sp = tcp_hdr->src_port;
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV4;
+ } else {
+ if (!do_swap) {
+ v4Tuple.sp = tcp_hdr->src_port;
+ v4Tuple.dp = tcp_hdr->dst_port;
+ } else {
+ v4Tuple.sp = tcp_hdr->dst_port;
+ v4Tuple.dp = tcp_hdr->src_port;
+ }
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV4_SPAN;
+ }
+ memcpy(&(flow_match.keyData), &v4Tuple, sizeof(v4Tuple));
+ } else {
+ if (!is_span) {
+ v6Tuple.dp = tcp_hdr->dst_port;
+ v6Tuple.sp = tcp_hdr->src_port;
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV6;
+ } else {
+ if (!do_swap) {
+ v6Tuple.sp = tcp_hdr->src_port;
+ v6Tuple.dp = tcp_hdr->dst_port;
+ } else {
+ v6Tuple.dp = tcp_hdr->src_port;
+ v6Tuple.sp = tcp_hdr->dst_port;
+ }
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV6_SPAN;
+ }
+ memcpy(&(flow_match.keyData), &v6Tuple, sizeof(v6Tuple));
+ }
+ flow_match.ipProtocolField = 6;
+ break;
+ }
+ case RTE_PTYPE_L4_UDP:
+ {
+ struct udp_hdr *udp_hdr = (struct udp_hdr *) (packet + ntpv->dyn3->offset1);
+ if (layer3 == RTE_PTYPE_L3_IPV4) {
+ if (!is_span) {
+ v4Tuple.dp = udp_hdr->dst_port;
+ v4Tuple.sp = udp_hdr->src_port;
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV4;
+ } else {
+ if (!do_swap) {
+ v4Tuple.sp = udp_hdr->src_port;
+ v4Tuple.dp = udp_hdr->dst_port;
+ } else {
+ v4Tuple.dp = udp_hdr->src_port;
+ v4Tuple.sp = udp_hdr->dst_port;
+ }
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV4_SPAN;
+ }
+ memcpy(&(flow_match.keyData), &v4Tuple, sizeof(v4Tuple));
+ } else { /* layer3 is IPV6 */
+ if (!is_span) {
+ v6Tuple.dp = udp_hdr->dst_port;
+ v6Tuple.sp = udp_hdr->src_port;
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV6;
+ } else {
+ if (!do_swap) {
+ v6Tuple.sp = udp_hdr->src_port;
+ v6Tuple.dp = udp_hdr->dst_port;
+ } else {
+ v6Tuple.dp = udp_hdr->src_port;
+ v6Tuple.sp = udp_hdr->dst_port;
+ }
+ flow_match.keyId = NAPATECH_KEYTYPE_IPV6_SPAN;
+ }
+ memcpy(&(flow_match.keyData), &v6Tuple, sizeof(v6Tuple));
+ }
+ flow_match.ipProtocolField = 17;
+ break;
+ }
+ default:
+ {
+ return 0;
+ }
+ }
+
+ flow_match.op = 1; /* program flow */
+ flow_match.gfi = 1; /* Generate FlowInfo records */
+ flow_match.tau = 1; /* tcp automatic unlearn */
+
+ if (PACKET_TEST_ACTION(p, ACTION_DROP)) {
+ flow_match.keySetId = NAPATECH_FLOWTYPE_DROP;
+ } else {
+ if (is_inline) {
+ flow_match.keySetId = NAPATECH_FLOWTYPE_PASS;
+ } else {
+ flow_match.keySetId = NAPATECH_FLOWTYPE_DROP;
+ }
+ }
+
+ status = NT_FlowWrite(*phFlowStream, &flow_match, -1);
+ if (status == NT_STATUS_TIMEOUT) {
+ SCLogInfo("NT_FlowWrite returned NT_STATUS_TIMEOUT");
+ } else if (status != NT_SUCCESS) {
+ SCLogError(SC_ERR_NAPATECH_OPEN_FAILED,"NT_FlowWrite failed!.");
+ exit(EXIT_FAILURE);
+ }
+
+ return 1;
+}
+
+/**
+ * \brief Callback from Suricata when a flow that should be bypassed
+ * is identified.
+ */
+
+static int NapatechBypassCallback(Packet *p)
+{
+ NapatechPacketVars *ntpv = &(p->ntpv);
+
+ /*
+ * Since, at this point, we don't know what action to take,
+ * simply mark this packet as one that should be
+ * bypassed when the packet is returned by suricata with a
+ * pass/drop verdict.
+ */
+ ntpv->bypass = 1;
+
+ return 1;
+}
+
+#endif
+
/**
* \brief Initialize the Napatech receiver thread, generate a single
* NapatechThreadVar structure for each thread, this will
static PacketQueue packets_to_release[MAX_STREAMS];
+/**
+ * \brief Callback to indicate that the packet buffer can be returned to the hardware.
+ *
+ * Called when Suricata is done processing the packet. The packet is placed into
+ * a queue so that it can be retrieved and released by the packet processing thread.
+ *
+ * \param p Packet to return to the system.
+ *
+ */
static void NapatechReleasePacket(struct Packet_ *p)
{
PacketFreeOrRelease(p);
PacketEnqueue(&packets_to_release[p->ntpv.stream_id], p);
}
+/**
+ * \brief Returns the NUMA node associated with the currently running thread.
+ *
+ * \return ID of the NUMA node.
+ *
+ */
static int GetNumaNode(void)
{
int cpu = 0;
return node;
}
+/**
+ * \brief Outputs hints on the optimal host-buffer configuration to aid tuning.
+ *
+ * \param log_level of the currently running instance.
+ *
+ */
static void RecommendNUMAConfig(SCLogLevel log_level)
{
char string0[16];
SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
"Minimum host buffers that should be defined in ntservice.ini:");
- SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
- " NUMA Node 0: %d", (SC_ATOMIC_GET(numa0_count)));
+ SCLog(log_level, __FILE__, __FUNCTION__, __LINE__, " NUMA Node 0: %d",
+ (SC_ATOMIC_GET(numa0_count)));
- if (numa_max_node() >= 1) SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
- " NUMA Node 1: %d ", (SC_ATOMIC_GET(numa1_count)));
+ if (numa_max_node() >= 1)
+ SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
+ " NUMA Node 1: %d ", (SC_ATOMIC_GET(numa1_count)));
- if (numa_max_node() >= 2) SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
- " NUMA Node 2: %d ", (SC_ATOMIC_GET(numa2_count)));
+ if (numa_max_node() >= 2)
+ SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
+ " NUMA Node 2: %d ", (SC_ATOMIC_GET(numa2_count)));
- if (numa_max_node() >= 3) SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
- " NUMA Node 3: %d ", (SC_ATOMIC_GET(numa3_count)));
+ if (numa_max_node() >= 3)
+ SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
+ " NUMA Node 3: %d ", (SC_ATOMIC_GET(numa3_count)));
snprintf(string0, 16, "[%d, 16, 0]", SC_ATOMIC_GET(numa0_count));
snprintf(string1, 16, (numa_max_node() >= 1 ? ",[%d, 16, 1]" : ""),
SC_ATOMIC_GET(numa3_count));
SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
- "E.g.: HostBuffersRx=%s%s%s%s", string0, string1, string2, string3);
+ "E.g.: HostBuffersRx=%s%s%s%s", string0, string1, string2,
+ string3);
} else if (log_level == SC_LOG_ERROR) {
SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
- "Or, try running /opt/napatech3/bin/ntpl -e \"delete=all\" to clean-up stream NUMA config.");
+ "Or, try running /opt/napatech3/bin/ntpl -e \"delete=all\" to clean-up stream NUMA config.");
}
}
-TmEcode NapatechPacketLoopZC(ThreadVars *tv, void *data, void *slot)
+/**
+ * \brief Main Napatechpacket processing loop
+ *
+ * \param tv Thread variable to ThreadVars
+ * \param data Pointer to NapatechThreadVars with data specific to Napatech
+ * \param slot TMSlot where this instance is running.
+ *
+ */
+TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot)
{
int32_t status;
char error_buffer[100];
uint64_t hba_pkt_drops = 0;
uint64_t hba_byte_drops = 0;
uint16_t hba_pkt = 0;
- uint32_t filter_id = 0;
- uint32_t hash_id = 0;
- uint32_t numa_node = 0;
+ int numa_node = -1;
int set_cpu_affinity = 0;
-
+ int closer = 0;
+ int is_inline = 0;
+ int is_autoconfig = 0;
/* This just keeps the startup output more orderly. */
usleep(200000 * ntv->stream_id);
- if (NapatechIsAutoConfigEnabled()) {
+ if (ConfGetBool("napatech.inline", &is_inline) == 0) {
+ is_inline = 0;
+ }
+ if (ConfGetBool("napatech.auto-config", &is_autoconfig) == 0) {
+ is_autoconfig = 0;
+ }
+
+ if (is_autoconfig) {
numa_node = GetNumaNode();
switch (numa_node) {
- case 0: SC_ATOMIC_ADD(numa0_count, 1);
- break;
- case 1: SC_ATOMIC_ADD(numa1_count, 1);
- break;
- case 2: SC_ATOMIC_ADD(numa2_count, 1);
- break;
- case 3: SC_ATOMIC_ADD(numa3_count, 1);
- break;
- default: break;
+ case 0:
+ SC_ATOMIC_ADD(numa0_count, 1);
+ break;
+ case 1:
+ SC_ATOMIC_ADD(numa1_count, 1);
+ break;
+ case 2:
+ SC_ATOMIC_ADD(numa2_count, 1);
+ break;
+ case 3:
+ SC_ATOMIC_ADD(numa3_count, 1);
+ break;
+ default:
+ break;
}
if (ConfGetBool("threading.set-cpu-affinity", &set_cpu_affinity) != 1) {
if (set_cpu_affinity) {
NapatechSetupNuma(ntv->stream_id, numa_node);
}
- }
- if (NapatechIsAutoConfigEnabled()) {
numa_node = GetNumaNode();
SC_ATOMIC_ADD(stream_count, 1);
if (SC_ATOMIC_GET(stream_count) == NapatechGetNumConfiguredStreams()) {
- /* The last thread to run sets up the streams */
- status = NapatechSetupTraffic(NapatechGetNumFirstStream(),
- NapatechGetNumLastStream(),
- &filter_id, &hash_id);
- if (filter_id == 0) {
+#ifdef NAPATECH_ENABLE_BYPASS
+ /* Initialize the port map before we setup traffic filters */
+ for (int i = 0; i < MAX_PORTS; ++i) {
+ inline_port_map[i] = -1;
+ }
+#endif
+ /* The last thread to run sets up and deletes the streams */
+ status = NapatechSetupTraffic(NapatechGetNumFirstStream(),
+ NapatechGetNumLastStream());
- if (status == 0x20002061) {
- SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
- "Check host buffer configuration in ntservice.ini.");
- RecommendNUMAConfig(SC_LOG_ERROR);
+ closer = 1;
- } else if (filter_id == 0x20000008) {
- SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
- "Check napatech.ports in the suricata config file.");
- }
+ if (status == 0x20002061) {
+ SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
+ "Check host buffer configuration in ntservice.ini.");
+ RecommendNUMAConfig(SC_LOG_ERROR);
+ exit(EXIT_FAILURE);
+ } else if (status == 0x20000008) {
+ SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
+ "Check napatech.ports in the suricata config file.");
exit(EXIT_FAILURE);
}
-
- RecommendNUMAConfig(SC_LOG_INFO);
+ RecommendNUMAConfig(SC_LOG_PERF);
+ SCLogNotice("Napatech packet input engine started.");
}
- }
+ } // is_autoconfig
- SCLogInfo("Napatech Packet Loop Started - cpu: %3d, cpu_numa: %3d stream: %3u ",
+ SCLogInfo(
+ "Napatech Packet Loop Started - cpu: %3d, cpu_numa: %3d stream: %3u ",
sched_getcpu(), numa_node, ntv->stream_id);
if (ntv->hba > 0) {
SCLogDebug("Opening NAPATECH Stream: %lu for processing", ntv->stream_id);
if ((status = NT_NetRxOpen(&(ntv->rx_stream), "SuricataStream",
- NT_NET_INTERFACE_PACKET, ntv->stream_id, ntv->hba)) != NT_SUCCESS) {
+ NT_NET_INTERFACE_PACKET, ntv->stream_id, ntv->hba)) != NT_SUCCESS) {
NAPATECH_ERROR(SC_ERR_NAPATECH_OPEN_FAILED, status);
SCFree(ntv);
SCReturnInt(TM_ECODE_FAILED);
}
-
TmSlot *s = (TmSlot *) slot;
ntv->slot = s->slot_next;
/* Napatech returns packets 1 at a time */
status = NT_NetRxGet(ntv->rx_stream, &packet_buffer, 1000);
- if (unlikely(status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) {
+ if (unlikely(
+ status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) {
continue;
} else if (unlikely(status != NT_SUCCESS)) {
NAPATECH_ERROR(SC_ERR_NAPATECH_OPEN_FAILED, status);
- SCLogInfo("Failed to read from Napatech Stream%d: %s",
+ SCLogInfo("Failed to read from Napatech Stream %d: %s",
ntv->stream_id, error_buffer);
- SCReturnInt(TM_ECODE_FAILED);
+ break;
}
Packet *p = PacketGetFromQueueOrAlloc();
+#ifdef NAPATECH_ENABLE_BYPASS
+ p->ntpv.bypass = 0;
+#endif
+
if (unlikely(p == NULL)) {
NT_NetRxRelease(ntv->rx_stream, packet_buffer);
SCReturnInt(TM_ECODE_FAILED);
break;
case NT_TIMESTAMP_TYPE_PCAP_NANOTIME:
p->ts.tv_sec = pkt_ts >> 32;
- p->ts.tv_usec = ( (pkt_ts & 0xFFFFFFFF) / 1000)
- + (pkt_ts % 1000) > 500 ? 1 : 0;
+ p->ts.tv_usec = ((pkt_ts & 0xFFFFFFFF) / 1000) + (pkt_ts % 1000) > 500 ? 1 : 0;
break;
case NT_TIMESTAMP_TYPE_NATIVE_NDIS:
/* number of seconds between 1/1/1601 and 1/1/1970 */
p->ts.tv_sec = (pkt_ts / 100000000) - 11644473600;
- p->ts.tv_usec = ( (pkt_ts % 100000000) / 100)
- + (pkt_ts % 100) > 50 ? 1 : 0;
+ p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0;
break;
default:
SCLogError(SC_ERR_NAPATECH_TIMESTAMP_TYPE_NOT_SUPPORTED,
/* Update drop counter */
if (unlikely((status = NT_NetRxRead(ntv->rx_stream, &stat_cmd)) != NT_SUCCESS)) {
NAPATECH_ERROR(SC_ERR_NAPATECH_OPEN_FAILED, status);
- SCLogInfo("Couldn't retrieve drop statistics from the RX stream: %u - %s",
- ntv->stream_id, error_buffer);
+ SCLogInfo("Couldn't retrieve drop statistics from the RX stream: %u",
+ ntv->stream_id);
} else {
hba_pkt_drops = stat_cmd.u.streamDrop.pktsDropped;
StatsSyncCountersIfSignalled(tv);
}
+#ifdef NAPATECH_ENABLE_BYPASS
+ p->ntpv.dyn3 = _NT_NET_GET_PKT_DESCR_PTR_DYN3(packet_buffer);
+ p->BypassPacketsFlow = (NapatechIsBypassSupported() ? NapatechBypassCallback : NULL);
+ NT_NET_SET_PKT_TXPORT(packet_buffer, inline_port_map[p->ntpv.dyn3->rxPort]);
+#endif
p->ReleasePacket = NapatechReleasePacket;
p->ntpv.nt_packet_buf = packet_buffer;
p->ntpv.stream_id = ntv->stream_id;
p->datalink = LINKTYPE_ETHERNET;
- if (unlikely(PacketSetData(p,
- (uint8_t *) NT_NET_GET_PKT_L2_PTR(packet_buffer),
- NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) {
-
+ if (unlikely(PacketSetData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) {
TmqhOutputPacketpool(ntv->tv, p);
NT_NetRxRelease(ntv->rx_stream, packet_buffer);
SCReturnInt(TM_ECODE_FAILED);
/* Release any packets that were returned by the callback function */
Packet *rel_pkt = PacketDequeue(&packets_to_release[ntv->stream_id]);
while (rel_pkt != NULL) {
+#ifdef NAPATECH_ENABLE_BYPASS
+ if (rel_pkt->ntpv.bypass == 1) {
+ if (PACKET_TEST_ACTION(p, ACTION_DROP)) {
+ if (is_inline) {
+ rel_pkt->ntpv.dyn3->wireLength = 0;
+ }
+ }
+ ProgramFlow(rel_pkt, is_inline);
+ }
+#endif
NT_NetRxRelease(ntv->rx_stream, rel_pkt->ntpv.nt_packet_buf);
rel_pkt = PacketDequeue(&packets_to_release[ntv->stream_id]);
}
StatsSyncCountersIfSignalled(tv);
- }
-
- if (filter_id) {
- NapatechDeleteFilter(filter_id);
- }
+ } // while
- if (hash_id) {
- NapatechDeleteFilter(hash_id);
+ if (closer) {
+#ifdef NAPATECH_ENABLE_BYPASS
+ NapatechCloseFlowStreams();
+#endif
+ NapatechDeleteFilters();
}
if (unlikely(ntv->hba > 0)) {
- SCLogInfo("Host Buffer Allowance Drops - pkts: %ld, bytes: %ld",
- hba_pkt_drops, hba_byte_drops);
+ SCLogInfo("Host Buffer Allowance Drops - pkts: %ld, bytes: %ld", hba_pkt_drops, hba_byte_drops);
}
SCReturnInt(TM_ECODE_OK);
NapatechCurrentStats stat = NapatechGetCurrentStats(ntv->stream_id);
double percent = 0;
- if (stat.current_drops > 0)
- percent = (((double) stat.current_drops)
- / (stat.current_packets + stat.current_drops)) * 100;
+ if (stat.current_drop_packets > 0)
+ percent = (((double) stat.current_drop_packets)
+ / (stat.current_packets + stat.current_drop_packets)) * 100;
SCLogInfo("nt%lu - pkts: %lu; drop: %lu (%5.2f%%); bytes: %lu",
- (uint64_t) ntv->stream_id, stat.current_packets,
- stat.current_drops, percent, stat.current_bytes);
+ (uint64_t) ntv->stream_id, stat.current_packets,
+ stat.current_drop_packets, percent, stat.current_bytes);
SC_ATOMIC_ADD(total_packets, stat.current_packets);
- SC_ATOMIC_ADD(total_drops, stat.current_drops);
+ SC_ATOMIC_ADD(total_drops, stat.current_drop_packets);
SC_ATOMIC_ADD(total_tallied, 1);
if (SC_ATOMIC_GET(total_tallied) == NapatechGetNumConfiguredStreams()) {
if (SC_ATOMIC_GET(total_drops) > 0)
percent = (((double) SC_ATOMIC_GET(total_drops)) / (SC_ATOMIC_GET(total_packets)
- + SC_ATOMIC_GET(total_drops))) * 100;
+ + SC_ATOMIC_GET(total_drops))) * 100;
SCLogInfo(" ");
SCLogInfo("--- Total Packets: %ld Total Dropped: %ld (%5.2f%%)",
SC_ATOMIC_GET(total_packets), SC_ATOMIC_GET(total_drops), percent);
+
+#ifdef NAPATECH_ENABLE_BYPASS
+ SCLogInfo("--- BypassCB - Total: %ld, UDP: %ld, TCP: %ld, Unhandled: %ld",
+ SC_ATOMIC_GET(flow_callback_cnt),
+ SC_ATOMIC_GET(flow_callback_udp_pkts),
+ SC_ATOMIC_GET(flow_callback_tcp_pkts),
+ SC_ATOMIC_GET(flow_callback_unhandled_pkts));
+#endif
}
}
{
SCEnter();
NapatechThreadVars *ntv = (NapatechThreadVars *) data;
+
SCLogDebug("Closing Napatech Stream: %d", ntv->stream_id);
NT_NetRxClose(ntv->rx_stream);
+
SCReturnInt(TM_ECODE_OK);
}
-/** Decode Napatech */
-
/**
* \brief This function passes off to link type decoders.
*
break;
default:
SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED,
- "Error: datalink type %" PRId32 " not yet supported in module NapatechDecode",
+ "Datalink type %" PRId32 " not yet supported in module NapatechDecode",
p->datalink);
break;
}
SCReturnInt(TM_ECODE_OK);
}
+/**
+ * \brief Initialization of Napatech Thread.
+ *
+ * \param t pointer to ThreadVars
+ * \param initdata - unused.
+ * \param data pointer that gets cast into DecoderThreadVars
+ */
TmEcode NapatechDecodeThreadInit(ThreadVars *tv, const void *initdata, void **data)
{
SCEnter();
DecodeThreadVars *dtv = NULL;
dtv = DecodeThreadVarsAlloc(tv);
- if (dtv == NULL)
+ if (dtv == NULL) {
SCReturnInt(TM_ECODE_FAILED);
+ }
DecodeRegisterPerfCounters(dtv, tv);
*data = (void *) dtv;
SCReturnInt(TM_ECODE_OK);
}
+/**
+ * \brief Deinitialization of Napatech Thread.
+ *
+ * \param tv pointer to ThreadVars
+ * \param data pointer that gets cast into DecoderThreadVars
+ */
TmEcode NapatechDecodeThreadDeinit(ThreadVars *tv, void *data)
{
- if (data != NULL)
+ if (data != NULL) {
DecodeThreadVarsFree(tv, data);
+ }
SCReturnInt(TM_ECODE_OK);
}
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
-
/**
* \file
*
*
*
*/
-
#include "suricata-common.h"
+
#ifdef HAVE_NAPATECH
#include "suricata.h"
#include "util-device.h"
#include "util-cpu.h"
+#include "util-byte.h"
#include "threadvars.h"
#include "tm-threads.h"
+#include "util-napatech.h"
+#include "source-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 NtFlowStream_t hFlowStream[MAX_ADAPTERS];
+
+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.
+ */
+static int GetNumAdapters(void)
+{
+ NtInfoStream_t hInfo;
+ NtInfo_t hInfoSys;
+ int status;
+
+ if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_OPEN_FAILED, status);
+ exit(EXIT_FAILURE);
+ }
+
+ hInfoSys.cmd = NT_INFO_CMD_READ_SYSTEM;
+ if ((status = NT_InfoRead(hInfo, &hInfoSys)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_OPEN_FAILED, status);
+ exit(EXIT_FAILURE);
+ }
+
+ int num_adapters = hInfoSys.u.system.data.numAdapters;
+
+ NT_InfoClose(hInfo);
+ return num_adapters;
+}
+
+/**
+ * \brief Initializes the FlowStreams used to program flow data.
+ *
+ * Opens a FlowStream on each adapter present in the system. This
+ * FlowStream is subsequently used to program the adapter with
+ * flows to bypass.
+ *
+ * \return 1 if Bypass functionality is supported; zero otherwise.
+ */
+int NapatechInitFlowStreams(void)
+{
+ int status;
+ int adapter = 0;
+ int num_adapters = GetNumAdapters();
+ SCLogInfo("Found %d Napatech adapters.\n", num_adapters);
+ memset(&hFlowStream, 0, sizeof(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[adapter], flow_name, &attr)) != NT_SUCCESS) {
+ SCLogWarning(SC_WARN_COMPATIBILITY, "Napatech bypass functionality not supported by the FPGA version on adapter %d - disabling support.", adapter);
+ bypass_supported = 0;
+ return 0;
+ }
+ }
+
+ bypass_supported = 1;
+ return bypass_supported;
+}
+
+/**
+ * \brief Returns a pointer to the FlowStream associated with this adapter.
+ *
+ * \return count of the Napatech adapters present in the system.
+ */
+NtFlowStream_t *NapatechGetFlowStreamPtr(int device)
+{
+ return &hFlowStream[device];
+}
+
+/**
+ * \brief Closes all open FlowStreams
+ *
+ * \return Success of the operation.
+ */
+int NapatechCloseFlowStreams(void)
+{
+ int status = 0;
+ int adapter = 0;
+ int num_adapters = GetNumAdapters();
+
+ for (adapter = 0; adapter < num_adapters; ++adapter) {
+ if (hFlowStream[adapter]) {
+ SCLogInfo("Closing Napatech Flow Stream on adapter %d.", adapter);
+ if ((status = NT_FlowClose(hFlowStream[adapter])) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_SHUTDOWN, status);
+ }
+ hFlowStream[adapter] = NULL;
+ }
+ }
+ return (status == NT_SUCCESS);
+}
+
+
+/**
+ * \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 < GetNumAdapters(); ++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(SC_ERR_NAPATECH_INIT_FAILED, 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 StreamCounters_ {
+typedef struct PacketCounters_
+{
uint16_t pkts;
uint16_t byte;
- uint16_t drop;
-} StreamCounters;
-
+ uint16_t drop_pkts;
+ uint16_t drop_byte;
+} PacketCounters;
+NapatechCurrentStats total_stats;
NapatechCurrentStats current_stats[MAX_STREAMS];
NapatechCurrentStats NapatechGetCurrentStats(uint16_t id)
#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 hStatStream,
+ 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;
- char buffer[80]; // Error buffer
NtStatistics_t stat; // Stat handle.
/* Check to see if it is an active stream */
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(hStatStream, &stat)) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, buffer, sizeof (buffer));
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_StatRead():2 failed: %s\n", buffer);
+ if ((status = NT_StatRead(hstat_stream, &stat)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return 0;
}
return num_active;
}
+/**
+ * \brief Updates Napatech packet counters
+ *
+ * \param tv Pointer to TheardVars 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 hStatStream,
+ NtStatStream_t hstat_stream,
uint16_t num_streams,
NapatechStreamConfig stream_config[],
- StreamCounters streamCounters[]
+ 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 dropStart[MAX_STREAMS] = {0};
+ static uint64_t dropPktStart[MAX_STREAMS] = {0};
+ static uint64_t dropByteStart[MAX_STREAMS] = {0};
int status;
- char error_buffer[80]; // Error buffer
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) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_InfoRead() failed: %s\n", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
uint16_t num_active;
- if ((num_active = TestStreamConfig(hInfo, hStatStream,
- stream_config, num_streams)) == 0) {
+ if ((num_active = TestStreamConfig(hInfo, hstat_stream, stream_config, num_streams)) == 0) {
/* None of the configured streams are active */
return 0;
}
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;
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(hStatStream, &hStat)) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_StatRead() failed: %s\n", error_buffer);
+ if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return 0;
}
uint16_t stream_id = stream_config[inst_id].stream_id;
if (stream_config[inst_id].is_active) {
- uint64_t rxPktsTotal = 0;
- uint64_t rxByteTotal = 0;
- uint64_t dropTotal = 0;
+ 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 == false)) {
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;
- dropStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames;
+ 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 {
- rxPktsTotal += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.frames;
- rxByteTotal += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.bytes;
- dropTotal += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames;
+ 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 = rxPktsTotal - rxPktsStart[stream_id];
- current_stats[stream_id].current_bytes = rxByteTotal - rxByteStart[stream_id];
- current_stats[stream_id].current_drops = dropTotal - dropStart[stream_id];
+ 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);
}
- StatsSetUI64(tv, streamCounters[inst_id].pkts, current_stats[stream_id].current_packets);
- StatsSetUI64(tv, streamCounters[inst_id].byte, current_stats[stream_id].current_bytes);
- StatsSetUI64(tv, streamCounters[inst_id].drop, current_stats[stream_id].current_drops);
-
++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(SC_ERR_NAPATECH_INIT_FAILED, 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 < GetNumAdapters(); ++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 retrieives
+ * statistics from the Napatech card and updates the packet counters
+ *
+ * \param arg Pointer that is caste into a TheardVars structure
+ */
static void *NapatechStatsLoop(void *arg)
{
ThreadVars *tv = (ThreadVars *) arg;
int status;
- char error_buffer[80]; // Error buffer
NtInfoStream_t hInfo;
- NtStatStream_t hStatStream;
+ 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) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_RUNMODE, "NT_InfoOpen() failed: %s\n", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return NULL;
}
- if ((status = NT_StatOpen(&hStatStream, "StatsLoopStatsStream")) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_RUNMODE, "NT_StatOpen() failed: %s\n", error_buffer);
+ if ((status = NT_StatOpen(&hstat_stream, "StatsLoopStatsStream")) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return NULL;
}
- StreamCounters streamCounters[MAX_STREAMS];
- for (int i = 0; i < stream_cnt; ++i) {
- char *pkts_buf = SCCalloc(1, 32);
- if (unlikely(pkts_buf == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC,
- "Failed to allocate memory for NAPATECH stream counter.");
- exit(EXIT_FAILURE);
- }
+ NtStatistics_t hStat;
+ memset(&hStat, 0, sizeof (NtStatistics_t));
- snprintf(pkts_buf, 32, "nt%d.pkts", stream_config[i].stream_id);
- streamCounters[i].pkts = StatsRegisterCounter(pkts_buf, tv);
+#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 */
- char *byte_buf = SCCalloc(1, 32);
- if (unlikely(byte_buf == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC,
- "Failed to allocate memory for NAPATECH stream counter.");
- exit(EXIT_FAILURE);
- }
- snprintf(byte_buf, 32, "nt%d.bytes", stream_config[i].stream_id);
- streamCounters[i].byte = StatsRegisterCounter(byte_buf, tv);
+ if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
+ return 0;
+ }
- char *drop_buf = SCCalloc(1, 32);
- if (unlikely(drop_buf == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC,
- "Failed to allocate memory for NAPATECH stream counter.");
- exit(EXIT_FAILURE);
+ 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)) {
+ SCLogError(SC_ERR_MEM_ALLOC,
+ "Failed to allocate memory for NAPATECH stream counter.");
+ exit(EXIT_FAILURE);
+ }
+
+ 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)) {
+ SCLogError(SC_ERR_MEM_ALLOC,
+ "Failed to allocate memory for NAPATECH stream counter.");
+ exit(EXIT_FAILURE);
+ }
+ 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)) {
+ SCLogError(SC_ERR_MEM_ALLOC,
+ "Failed to allocate memory for NAPATECH stream counter.");
+ exit(EXIT_FAILURE);
+ }
+ 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)) {
+ SCLogError(SC_ERR_MEM_ALLOC,
+ "Failed to allocate memory for NAPATECH stream counter.");
+ exit(EXIT_FAILURE);
+ }
+ snprintf(drop_byte_buf, 32, "napa%d.drop_byte", stream_config[i].stream_id);
+ stream_counters[i].drop_byte = StatsRegisterCounter(drop_byte_buf, tv);
}
- snprintf(drop_buf, 32, "nt%d.drop", stream_config[i].stream_id);
- streamCounters[i].drop = StatsRegisterCounter(drop_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);
- for (int i = 0; i < stream_cnt; ++i) {
- StatsSetUI64(tv, streamCounters[i].pkts, 0);
- StatsSetUI64(tv, streamCounters[i].byte, 0);
- StatsSetUI64(tv, streamCounters[i].drop, 0);
+ 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, hStatStream,
- stream_cnt, stream_config, streamCounters);
+ 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);
break;
}
- UpdateStreamStats(tv, hInfo, hStatStream,
- stream_cnt, stream_config, streamCounters);
+ 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) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_RUNMODE, "NT_InfoClose() failed: %s\n", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return NULL;
}
/* Close the statistics stream */
- if ((status = NT_StatClose(hStatStream)) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_RUNMODE, "NT_StatClose() failed: %s\n", error_buffer);
+ if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return NULL;
}
-
SCLogDebug("Exiting NapatechStatsLoop");
TmThreadsSetFlag(tv, THV_RUNNING_DONE);
TmThreadWaitForFlag(tv, THV_DEINIT);
#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[])
+ 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 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 *root = ConfGetNode("threading.cpu-affinity");
if (root != NULL) {
+
TAILQ_FOREACH(affinity, &root->head, next)
{
if (strcmp(affinity->val, "decode-cpu-set") == 0 ||
char copystr[16];
strlcpy(copystr, lnode->val, 16);
- start = atoi(copystr);
- end = atoi(strchr(copystr, '-') + 1);
+ ByteExtractStringUint8(&start, 10, 0, copystr);
+ ByteExtractStringUint8(&end, 10, 0, strchr(copystr, '-') + 1);
+
worker_count = end - start + 1;
} else {
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 hStatStream;
+ NtStatStream_t hstat_stream;
NtStatistics_t hStat; // Stat handle.
NtInfoStream_t info_stream;
NtInfo_t info;
}
if ((status = NT_InfoOpen(&info_stream, "SuricataStreamInfo")) != NT_SUCCESS) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
- "NT_InfoOpen failed: %s", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, status);
return -1;
}
- if ((status = NT_StatOpen(&hStatStream, "StatsStream")) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_RUNMODE, "NT_StatOpen() failed: %s\n", error_buffer);
+ if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, status);
return -1;
}
if (use_all_streams) {
info.cmd = NT_INFO_CMD_READ_STREAM;
if ((status = NT_InfoRead(info_stream, &info)) != NT_SUCCESS) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
- "NT_InfoRead failed: %s", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, status);
return -1;
}
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
hStat.u.usageData_v0.streamid = (uint8_t) stream_id;
- if ((status = NT_StatRead(hStatStream, &hStat)) != NT_SUCCESS) {
+ if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
/* Get the status code as text */
NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_StatRead() failed: %s\n", error_buffer);
+ SCLogError(SC_ERR_NAPATECH_INIT_FAILED, "NT_StatRead() failed: %s\n", error_buffer);
return -1;
}
/* When not using the default streams we need to
* parse the array of streams from the conf */
if ((ntstreams = ConfGetNode("napatech.streams")) == NULL) {
- SCLogError(SC_ERR_RUNMODE,
- "Failed retrieving napatech.streams from Config");
+ SCLogError(SC_ERR_RUNMODE, "Failed retrieving napatech.streams from Config");
if (NapatechIsAutoConfigEnabled() && (set_cpu_affinity == 0)) {
SCLogError(SC_ERR_RUNMODE,
"if set-cpu-affinity: no in conf then napatech.streams must be defined");
{
if (stream == NULL) {
- SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
- "Couldn't Parse Stream Configuration");
+ SCLogError(SC_ERR_NAPATECH_INIT_FAILED, "Couldn't Parse Stream Configuration");
return -1;
}
char copystr[16];
strlcpy(copystr, stream->val, 16);
-
- start = atoi(copystr);
- end = atoi(strchr(copystr, '-') + 1);
+ ByteExtractStringUint16(&start, 10, 0, copystr);
+ ByteExtractStringUint16(&end, 10, 0, strchr(copystr, '-') + 1);
} else {
if (stream_spec == CONFIG_SPECIFIER_RANGE) {
SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
exit(EXIT_FAILURE);
}
stream_spec = CONFIG_SPECIFIER_INDIVIDUAL;
-
- stream_config[instance_cnt].stream_id = atoi(stream->val);
+ ByteExtractStringUint16(&stream_config[instance_cnt].stream_id, 10, 0, stream->val);
start = stream_config[instance_cnt].stream_id;
end = stream_config[instance_cnt].stream_id;
}
hStat.u.usageData_v0.streamid =
(uint8_t) stream_config[instance_cnt].stream_id;
- if ((status = NT_StatRead(hStatStream, &hStat)) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_StatRead() failed: %s\n", error_buffer);
+ if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return -1;
}
}
/* Close the statistics stream */
- if ((status = NT_StatClose(hStatStream)) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_RUNMODE, "NT_StatClose() failed: %s\n", error_buffer);
+ if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return -1;
}
if ((status = NT_InfoClose(info_stream)) != NT_SUCCESS) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED,
- "NT_InfoClose failed: %s", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
return -1;
}
NtInfo_t hStreamInfo;
NtStatistics_t hStat; // Stat handle.
NtInfoStream_t hInfo;
- NtStatStream_t hStatStream;
-
- char error_buffer[NT_ERRBUF_SIZE]; // Error buffer
+ 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};
/* Open the info and Statistics */
if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_InfoOpen() failed: %s\n", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
- if ((status = NT_StatOpen(&hStatStream, "StatsStream")) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_StatOpen() failed: %s\n", error_buffer);
+ if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, 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) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_InfoRead() failed: %s\n", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, 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) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_InfoRead() failed: %s\n", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
hStat.u.usageData_v0.streamid = (uint8_t) stream_id;
- if ((status = NT_StatRead(hStatStream, &hStat)) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED,
- "NT_StatRead() failed: %s\n", error_buffer);
+ if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
} 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++) {
+ 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
((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) {
-
+ while (ave_HB_fill_level[stream_id] >= HB_alert_level[stream_id] + alertInterval) {
HB_alert_level[stream_id] += alertInterval;
}
- SCLogInfo("nt%d - Increasing Host Buffer Fill Level : %4d%%",
+ 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))) {
- SCLogInfo("nt%d - Decreasing Host Buffer Fill Level: %4d%%",
+ 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)) {
}
}
+#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;
}
- SCLogInfo("nt%d - Increasing Adapter SDRAM Fill Level: %4d%%",
+ 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))) {
- SCLogInfo("nt%d - Decreasing Adapter SDRAM Fill Level : %4d%%",
+ 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)) {
}
}
}
+#endif /* NAPATECH_ENABLE_BYPASS */
}
++stream_id;
}
}
if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) {
- NT_ExplainError(status, error_buffer, sizeof (error_buffer) - 1);
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED, "NT_InfoClose() failed: %s\n", error_buffer);
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
/* Close the statistics stream */
- if ((status = NT_StatClose(hStatStream)) != NT_SUCCESS) {
- /* Get the status code as text */
- NT_ExplainError(status, error_buffer, sizeof (error_buffer));
- SCLogError(SC_ERR_NAPATECH_INIT_FAILED, "NT_StatClose() failed: %s\n", error_buffer);
+ if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) {
+ NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
return NULL;
}
+
void NapatechStartStats(void)
{
/* Creates the Statistic threads */
exit(EXIT_FAILURE);
}
+#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,
NtNtplInfo_t ntpl_info;
if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) {
-
NAPATECH_ERROR(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, status);
return false;
}
return status;
}
-static bool NapatechSetHashmode(uint32_t *filter_id)
+static uint32_t NapatechSetHashmode(void)
{
uint32_t status = 0;
const char *hash_mode;
char ntpl_cmd[64];
NtNtplInfo_t ntpl_info;
- *filter_id = 0;
+ uint32_t filter_id = 0;
/* Get the hashmode from the conf file. */
ConfGetValue("napatech.hashmode", &hash_mode);
if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info,
NT_NTPL_PARSER_VALIDATE_NORMAL)) == NT_SUCCESS) {
- *filter_id = ntpl_info.ntplId;
- SCLogInfo("Napatech hashmode: %s ID: %d", hash_mode, status);
+ 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 status;
+ return filter_id;
}
static uint32_t GetStreamNUMAs(uint32_t stream_id, int stream_numas[])
{
NtStatistics_t hStat; // Stat handle.
- NtStatStream_t hStatStream;
+ NtStatStream_t hstat_stream;
int status; // Status variable
for (int i = 0; i < MAX_HOSTBUFFERS; ++i)
stream_numas[i] = -1;
- if ((status = NT_StatOpen(&hStatStream, "StatsStream")) != NT_SUCCESS) {
+ if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) {
NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0;
hStat.u.usageData_v0.streamid = (uint8_t) stream_id;
- if ((status = NT_StatRead(hStatStream, &hStat)) != NT_SUCCESS) {
+ if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) {
NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
exit(EXIT_FAILURE);
}
return hStat.u.usageData_v0.data.numHostBufferUsed;
}
-uint32_t NapatechSetupTraffic(uint32_t first_stream, uint32_t last_stream,
- uint32_t *filter_id, uint32_t *hash_id)
+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(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, 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
- char ports_spec[PORTS_SPEC_SIZE];
+ 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;
- bool first_iteration = true;
+ int iteration = 0;
int status = 0;
- static NtConfigStream_t hconfig;
- char ntpl_cmd[128];
+ NtConfigStream_t hconfig;
+ char ntpl_cmd[512];
+ int is_inline = 0;
+ int is_span_port[MAX_PORTS] = { 0 };
- NapatechSetHashmode(hash_id);
+ 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(SC_ERR_NAPATECH_INIT_FAILED, 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 {
+ SCLogInfo("Napatech Hardware Bypass available but disabled.");
+ }
+#else
+ if (NapatechUseHWBypass()) {
+ SCLogInfo("Napatech Hardware Bypass requested in conf but is not available.");
+ exit(EXIT_FAILURE);
+ } else {
+ SCLogInfo("Napatech Hardware Bypass disabled.");
+ }
+
+ if (is_inline) {
+ SCLogError(SC_ERR_RUNMODE, "Napatech inline mode not supported. (Only available when Hardware Bypass support is enabled.)");
+ exit(EXIT_FAILURE);
+ }
+#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
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)
{
exit(EXIT_FAILURE);
}
- uint8_t start, end;
- if (strncmp(port->val, "all", 3) == 0) {
- /* check that the sting in the config file is correctly specified */
- if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) {
- SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
- "Only one Napatech port specifier type allowed.");
- exit(EXIT_FAILURE);
- }
- stream_spec = CONFIG_SPECIFIER_RANGE;
+ if (NapatechUseHWBypass()) {
+#ifdef NAPATECH_ENABLE_BYPASS
+ if (strchr(port->val, '-')) {
+ stream_spec = CONFIG_SPECIFIER_RANGE;
- snprintf(ports_spec, sizeof(ports_spec), "all");
- } else if (strchr(port->val, '-')) {
- /* check that the sting in the config file is correctly specified */
- if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) {
- SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
- "Only one Napatech port specifier type allowed.");
- exit(EXIT_FAILURE);
- }
- stream_spec = CONFIG_SPECIFIER_RANGE;
+ char copystr[16];
+ strlcpy(copystr, port->val, sizeof(copystr));
+ ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, copystr);
+ ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0, strchr(copystr, '-')+1);
+
+ if (ports_spec.first[iteration] == ports_spec.second[iteration]) {
+ if (is_inline) {
+ SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
+ "Error with napatec.ports in conf file. When running in inline mode the two ports specifying a segment must be different.");
+ exit(EXIT_FAILURE);
+ } 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));
+ }
+
+ }
+ }
- char copystr[16];
- strlcpy(copystr, port->val, sizeof(copystr));
+ if (NapatechGetAdapter(ports_spec.first[iteration]) != NapatechGetAdapter(ports_spec.first[iteration])) {
+ SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
+ "Invalid napatech.ports specification in conf file.");
+ SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
+ "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);
+ }
- start = atoi(copystr);
- end = atoi(strchr(copystr, '-') + 1);
- snprintf(ports_spec, sizeof(ports_spec), "port == (%d..%d)", start, end);
+ 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]);
+ }
- } else {
- /* check that the sting in the config file is correctly specified */
- if (stream_spec == CONFIG_SPECIFIER_RANGE) {
+ 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 {
SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
- "Napatech port range specifiers cannot be combined with individual stream specifiers.");
+ "When using hardware flow bypass ports must be specified as segments. E.g. ports: [0-1, 0-2]");
exit(EXIT_FAILURE);
}
- stream_spec = CONFIG_SPECIFIER_INDIVIDUAL;
+#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) {
+ SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
+ "Only one Napatech port specifier type is allowed.");
+ exit(EXIT_FAILURE);
+ }
+ 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) {
+ SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
+ "Only one Napatech port specifier is allowed when hardware bypass is disabled. (E.g. ports: [0-4], NOT ports: [0-1,2-3])");
+ exit(EXIT_FAILURE);
+ }
+ stream_spec = CONFIG_SPECIFIER_RANGE;
- /* Determine the ports to use on the NTPL assign statement*/
- if (first_iteration) {
- snprintf(ports_spec, sizeof(ports_spec), "port==%s", port->val);
- first_iteration = false;
+ char copystr[16];
+ strlcpy(copystr, port->val, sizeof (copystr));
+ ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, copystr);
+ ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0, strchr(copystr, '-') + 1);
+ snprintf(ports_spec.str, sizeof (ports_spec.str), "(%d..%d)", ports_spec.first[iteration], ports_spec.second[iteration]);
} else {
- char temp[PORTS_SPEC_SIZE];
- snprintf(temp, sizeof(temp), "%s,%s",ports_spec,port->val);
- snprintf(ports_spec, sizeof(ports_spec), "%s", temp);
+ /* check that the sting in the config file is correctly specified */
+ if (stream_spec == CONFIG_SPECIFIER_RANGE) {
+ SCLogError(SC_ERR_NAPATECH_PARSE_CONFIG,
+ "Napatech port range specifiers cannot be combined with individual stream specifiers.");
+ exit(EXIT_FAILURE);
+ }
+ stream_spec = CONFIG_SPECIFIER_INDIVIDUAL;
+
+ ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, 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);
}
- }
- /* Build the NTPL command */
- snprintf(ntpl_cmd, sizeof(ntpl_cmd), "assign[streamid=(%d..%d)] = %s",
- first_stream, last_stream, ports_spec);
+ 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));
+ }
+ }
- NtNtplInfo_t ntpl_info;
+ 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 ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) {
- NAPATECH_ERROR(SC_ERR_NAPATECH_INIT_FAILED, status);
- exit(EXIT_FAILURE);
- }
+ 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 ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info,
- NT_NTPL_PARSER_VALIDATE_NORMAL)) == NT_SUCCESS) {
- *filter_id = ntpl_info.ntplId;
- status = ntpl_info.u.errorData.errCode;
- SCLogInfo("NTPL filter assignment \"%s\" returned filter id %4d",
- ntpl_cmd, *filter_id);
+ 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 {
- NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status);
- status = ntpl_info.u.errorData.errCode;
- return false;
+ if (is_inline) {
+ SCLogError(SC_WARN_COMPATIBILITY,
+ "Napatech Inline operation not supported by this FPGA version.");
+ exit(EXIT_FAILURE);
+ }
+
+ 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);
+ }
}
- SCLogInfo("Host-buffer NUMA assignments: ");
+#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) {
uint32_t num_host_buffers = GetStreamNUMAs(stream_id, numa_nodes);
- snprintf(temp1, 256, " stream %d:", stream_id);
+ snprintf(temp1, 256, " stream %d: ", stream_id);
for (uint32_t hb_id = 0; hb_id < num_host_buffers; ++hb_id) {
- snprintf(temp2, 256, "%s %d ", temp1, numa_nodes[hb_id]);
- snprintf(temp1, 256, "%s", temp2);
+ snprintf(temp2, 256, "%d ", numa_nodes[hb_id]);
+ strlcat(temp1, temp2, sizeof(temp1));
}
- SCLogInfo("%s", temp1);
+ SCLogConfig("%s", temp1);
}
- return status;
-}
-
-bool NapatechDeleteFilter(uint32_t filter_id)
-{
- uint32_t status = 0;
- static NtConfigStream_t hconfig;
- char ntpl_cmd[64];
- NtNtplInfo_t ntpl_info;
-
- /* issue an NTPL command to delete the filter */
- snprintf(ntpl_cmd, 64, "delete = %d", filter_id);
-
- if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) {
- NAPATECH_ERROR(SC_ERR_NAPATECH_STREAMS_REGISTER_FAILED, status);
- exit(EXIT_FAILURE);
- }
-
- if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info,
- NT_NTPL_PARSER_VALIDATE_NORMAL)) == NT_SUCCESS) {
- status = ntpl_info.ntplId;
- SCLogInfo("Removed Napatech filter %d. ", filter_id);
+ if (first_stream == last_stream) {
+ snprintf(ntpl_cmd, sizeof (ntpl_cmd),
+ "Setup[state=active] = StreamId == %d",
+ first_stream);
} else {
- NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status);
- status = 0;
+ 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;
}