endif ( NOT ENABLE_COREFILES )
set ( _LARGEFILE_SOURCE ${ENABLE_LARGE_PCAP} )
+set ( USE_TSC_CLOCK ${ENABLE_TSC_CLOCK} )
if ( ENABLE_LARGE_PCAP )
set ( _FILE_OFFSET_BITS 64 )
option ( ENABLE_COREFILES "Prevent Snort from generating core files" ON )
option ( ENABLE_INTEL_SOFT_CPM "Enable Intel Soft CPM support" OFF )
option ( ENABLE_LARGE_PCAP "Enable support for pcaps larger than 2 GB" OFF )
+option ( ENABLE_TSC_CLOCK "Use timestamp counter register clock (x86 only)" OFF )
# documentation
option ( MAKE_HTML_DOC "Create the HTML documentation" ON )
#cmakedefine _LARGEFILE_SOURCE 1
#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@
+/* enable ha capable build */
+#cmakedefine USE_TSC_CLOCK 1
/* platforms */
AC_DEFINE(SHELL, [1], [enable shell support])
fi
+AC_ARG_ENABLE(tsc-clock,
+ AS_HELP_STRING([--enable-tsc-clock],[use timestamp counter register clock (x86 only)]),
+ enable_tsc_clock="$enableval", enable_tsc_clock="no")
+
+if test "x$enable_tsc_clock" = "xyes"; then
+ AC_DEFINE(USE_TSC_CLOCK, [1], [enable tsc clock])
+fi
+
AC_ARG_ENABLE(large-pcap,
AS_HELP_STRING([--enable-large-pcap],[enable support for pcaps larger than 2 GB]),
enable_large_pcap="$enableval", enable_large_pcap="no")
--disable-static-codecs do not include codecs in binary
--enable-shell enable command line shell support
--enable-large-pcap enable support for pcaps larger than 2 GB
+ --enable-tsc-clock use timestamp counter register clock (x86 only)
--enable-debug-msgs enable debug printing options (bugreports and
developers only)
--enable-debug enable debugging options (bugreports and developers
--enable-large-pcap)
append_cache_entry ENABLE_LARGE_PCAP BOOL true
;;
+ --enable-tsc-clock)
+ append_cache_entry ENABLE_TSC_CLOCK BOOL true
+ ;;
--disable-large-pcap)
append_cache_entry ENABLE_LARGE_PCAP BOOL false
;;
detection
framework
file_api
- time
latency
profiler
+ time
ips_actions
events
hash
detection/libdetection.a \
framework/libframework.a \
file_api/libfile_api.a \
-time/libtime.a \
latency/liblatency.a \
profiler/libprofiler.a \
+time/libtime.a \
actions/libips_actions.a \
events/libevents.a \
hash/libhash.a \
{
{
PacketLatency::Context pkt_latency_ctx { p };
-
bool inspected = false;
// If the packet has errors, we won't analyze it.
THREAD_LOCAL uint64_t rule_eval_pkt_count = 0;
-THREAD_LOCAL OTNX_MATCH_DATA t_omd;
+static THREAD_LOCAL OTNX_MATCH_DATA t_omd;
/* initialize the global OTNX_MATCH_DATA variable */
void otnx_match_data_init(int num_rule_types)
static inline void InitMatchInfo(OTNX_MATCH_DATA* o)
{
- int i = 0;
+ for ( int i = 0; i < o->iMatchInfoArraySize; i++ )
+ o->matchInfo[i].iMatchCount = 0;
- for (i = 0; i < o->iMatchInfoArraySize; i++)
- {
- o->matchInfo[i].iMatchCount = 0;
- o->matchInfo[i].iMatchIndex = 0;
- o->matchInfo[i].iMatchMaxLen = 0;
- }
+ o->have_match = false;
}
// called by fpLogEvent(), which does the filtering etc.
** int - 1 max_events variable hit, 0 successful.
**
*/
-int fpAddMatch(OTNX_MATCH_DATA* omd_local, int pLen, const OptTreeNode* otn)
+int fpAddMatch(OTNX_MATCH_DATA* omd_local, int /*pLen*/, const OptTreeNode* otn)
{
- MATCH_INFO* pmi;
- int evalIndex;
- int i;
RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn);
-
- evalIndex = rtn->listhead->ruleListNode->evalIndex;
+ int evalIndex = rtn->listhead->ruleListNode->evalIndex;
/* bounds check index */
if ( evalIndex >= omd_local->iMatchInfoArraySize )
pc.match_limit++;
return 1;
}
- pmi = &omd_local->matchInfo[evalIndex];
+ MATCH_INFO* pmi = &omd_local->matchInfo[evalIndex];
/*
** If we hit the max number of unique events for any rule type alert,
return 1;
}
- /* Check that we are not storing the same otn again */
- for ( i=0; i< pmi->iMatchCount; i++ )
+ // don't store the same otn again
+ for ( int i=0; i< pmi->iMatchCount; i++ )
{
if ( pmi->MatchArray[ i ] == otn )
- {
- //LogMessage("fpAddMatch: storing the same otn...\n");
return 0;
- }
}
- /*
- ** Add the event to the appropriate list
- */
+ // add the event to the appropriate list
pmi->MatchArray[ pmi->iMatchCount ] = otn;
- /*
- ** This means that we are adding a NC rule
- ** and we only set the index to this rule
- ** if there is no content rules in the
- ** same array.
- */
- if (pLen > 0)
- {
- /*
- ** Event Comparison Function
- ** Here the largest content match is the
- ** priority
- */
- if ( pmi->iMatchMaxLen < pLen )
- {
- pmi->iMatchMaxLen = pLen;
- pmi->iMatchIndex = pmi->iMatchCount;
- }
- }
-
pmi->iMatchCount++;
-
+ omd_local->have_match = true;
return 0;
}
*/
static inline int fpFinalSelectEvent(OTNX_MATCH_DATA* o, Packet* p)
{
+ if ( !o->have_match )
+ return 0;
+
int i;
int j;
int k;
unsigned size;
int check_ports;
+ bool have_match;
MATCH_INFO* matchInfo;
int iMatchInfoArraySize;
using std::chrono::microseconds;
if ( v.is("max_time") )
- config.max_time =
- duration_cast<decltype(config.max_time)>(microseconds(v.get_long()));
+ {
+ long t = clock_ticks(v.get_long());
+ config.max_time = duration_cast<decltype(config.max_time)>(microseconds(t));
+ }
else if ( v.is("fastpath") )
config.fastpath = v.get_bool();
using std::chrono::milliseconds;
if ( v.is("max_time") )
- config.max_time =
- duration_cast<decltype(config.max_time)>(microseconds(v.get_long()));
-
+ {
+ long t = clock_ticks(v.get_long());
+ config.max_time = duration_cast<decltype(config.max_time)>(microseconds(t));
+ }
else if ( v.is("suspend") )
config.suspend = v.get_bool();
config.suspend_threshold = v.get_long();
else if ( v.is("max_suspend_time") )
- config.max_suspend_time =
- duration_cast<decltype(config.max_time)>(milliseconds(v.get_long()));
-
+ {
+ long t = clock_ticks(v.get_long());
+ config.max_suspend_time = duration_cast<decltype(config.max_time)>(milliseconds(t));
+ }
else if ( v.is("action") )
config.action =
static_cast<decltype(config.action)>(v.get_long());
#include "protocols/packet.h"
#include "sfip/sf_ip.h"
#include "time/clock_defs.h"
+
#include "latency_config.h"
#include "latency_timer.h"
#include "latency_util.h"
// helpers
// -----------------------------------------------------------------------------
-using DefaultClock = hr_clock;
-
struct Event
{
const Packet* packet;
bool fastpathed;
- typename DefaultClock::duration elapsed;
+ typename SnortClock::duration elapsed;
};
template<typename Clock>
os << ": ";
- os << duration_cast<microseconds>(e.elapsed).count() << " usec, [";
+ os << clock_usecs(duration_cast<microseconds>(e.elapsed).count()) << " usec, [";
os << e.packet->ptrs.ip_api.get_src() << " -> " <<
e.packet->ptrs.ip_api.get_dst() << "]";
// implementation
// -----------------------------------------------------------------------------
-template<typename Clock = DefaultClock>
+template<typename Clock = SnortClock>
class Impl
{
public:
if ( config->action & PacketLatencyConfig::LOG )
log_handler.handle(e);
- if ( timer.marked_as_fastpathed and (config->action & PacketLatencyConfig::ALERT) )
+ if ( config->action & PacketLatencyConfig::ALERT )
event_handler.handle(e);
}
#include "events/event_queue.h"
#include "log/messages.h"
#include "main/snort_config.h"
+
#include "latency_config.h"
#include "latency_rules.h"
#include "latency_stats.h"
// helpers
// -----------------------------------------------------------------------------
-using DefaultClock = hr_clock;
-
struct Event
{
enum Type
};
Type type;
- typename DefaultClock::duration elapsed;
+ typename SnortClock::duration elapsed;
detection_option_tree_root_t* root;
};
os << ": ";
- os << duration_cast<microseconds>(e.elapsed).count() << " usec, ";
+ os << clock_usecs(duration_cast<microseconds>(e.elapsed).count()) << " usec, ";
}
// FIXIT-L clean up rule latency logging; delete or make useful
// implementation
// -----------------------------------------------------------------------------
-template<typename Clock = DefaultClock, typename RuleTree = DefaultRuleInterface>
+template<typename Clock = SnortClock, typename RuleTree = DefaultRuleInterface>
class Impl
{
public:
// show statistics
// -----------------------------------------------------------------------------
-#define s_memory_table_title "Memory Profile Statistics"
+#define s_memory_table_title "memory profile"
namespace memory_stats
{
#include "catch/catch.hpp"
#endif
-static constexpr unsigned WIDTH = 40;
+static constexpr unsigned WIDTH = 50;
static constexpr char ENDL = '\n';
const StatsTable::Header StatsTable::HEADER { '=' };
private:
dot_node_state_t& stats;
- Stopwatch<hr_clock> sw;
+ Stopwatch<SnortClock> sw;
bool finished = false;
};
#include "catch/catch.hpp"
#endif
-#define s_time_table_title "Module Profile Statistics"
+#define s_time_table_title "module profile"
namespace time_stats
{
t << v.checks();
// total time
- t << duration_cast<microseconds>(v.elapsed()).count();
+ t << clock_usecs(duration_cast<microseconds>(v.elapsed()).count());
// avg/check
t << duration_cast<microseconds>(v.avg_check()).count();
private:
TimeProfilerStats& stats;
- Stopwatch<hr_clock> sw;
+ Stopwatch<SnortClock> sw;
bool stopped_once = false;
};
config = nullptr;
}
-ProfileStats* StreamIcmpModule::get_profile() const
-{ return &icmp_perf_stats; }
+ProfileStats* StreamIcmpModule::get_profile(
+ unsigned index, const char*& name, const char*& parent) const
+{
+ if ( index )
+ return nullptr;
+
+ name = MOD_NAME;
+ parent = "stream";
+ return &icmp_perf_stats;
+}
StreamIcmpConfig* StreamIcmpModule::get_data()
{
bool begin(const char*, int, SnortConfig*) override;
bool end(const char*, int, SnortConfig*) override;
- ProfileStats* get_profile() const override;
+ ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
const PegInfo* get_pegs() const override;
PegCount* get_counts() const override;
{
case 0:
name = "stream_ip";
- parent = nullptr;
+ parent = "stream";
return &ip_perf_stats;
case 1:
{
Flow* flow = p->flow;
- if (!p || !flow)
+ if ( !flow )
return;
if (flow->session_state & STREAM_STATE_CLOSED)
switch ( index )
{
case 0:
- name = "stream_tcp";
- parent = nullptr;
+ name = MOD_NAME;
+ parent = "stream";
return &s5TcpPerfStats;
case 1:
config = nullptr;
}
-ProfileStats* StreamUdpModule::get_profile() const
+ProfileStats* StreamUdpModule::get_profile(
+ unsigned index, const char*& name, const char*& parent) const
{
+ if ( index )
+ return nullptr;
+
+ name = MOD_NAME;
+ parent = "stream";
return &udp_perf_stats;
}
bool begin(const char*, int, SnortConfig*) override;
bool end(const char*, int, SnortConfig*) override;
- ProfileStats* get_profile() const override;
+ ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
const PegInfo* get_pegs() const override;
PegCount* get_counts() const override;
StreamUdpConfig* get_data();
periodic.cc
periodic.h
timersub.h
+ tsc_clock.cc
)
if ( ENABLE_UNIT_TESTS )
endif ( ENABLE_UNIT_TESTS )
set ( TIME_INCLUDES
- cpuclock.h
clock_defs.h
stopwatch.h
+ tsc_clock.h
)
add_library ( time STATIC
x_includedir = $(pkgincludedir)/time
x_include_HEADERS = \
-cpuclock.h \
clock_defs.h \
-stopwatch.h
+stopwatch.h \
+tsc_clock.h
libtime_a_SOURCES = \
+clock_defs.h \
packet_time.cc \
packet_time.h \
periodic.cc \
periodic.h \
-timersub.h \
-clock_defs.h \
-stopwatch.h
+stopwatch.h \
+timersub.h \
+tsc_clock.cc
if ENABLE_UNIT_TESTS
libtime_a_SOURCES += stopwatch_test.cc
#ifndef CLOCK_DEFS_H
#define CLOCK_DEFS_H
-#include <chrono>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_TSC_CLOCK
+#include "time/tsc_clock.h"
+using SnortClock = TscClock;
+#else
+#include <chrono>
using hr_clock = std::chrono::high_resolution_clock;
-using hr_duration = hr_clock::duration;
-using hr_time = hr_clock::time_point;
+using SnortClock = hr_clock;
+inline long clock_scale() { return 1.0; }
+#endif
+
+using hr_duration = SnortClock::duration;
+using hr_time = SnortClock::time_point;
inline constexpr hr_duration operator "" _ticks (unsigned long long int v)
{ return hr_duration(v); }
using time_point = TimePoint;
using rep = Rep;
};
+
+inline long clock_usecs(long ticks)
+{ return ticks / clock_scale(); }
+
+inline long clock_ticks(long usecs)
+{ return usecs * clock_scale(); }
+
#endif
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2006-2013 Sourcefire, Inc.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation. You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// 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 along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//--------------------------------------------------------------------------
-
-#ifndef CPUCLOCK_H
-#define CPUCLOCK_H
-
-// Assembly to find clock ticks
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <unistd.h>
-
-// INTEL LINUX/BSD/..
-#if (defined(__i386) || defined(__amd64) || defined(__x86_64__))
-#define get_clockticks(val) \
-{ \
- uint32_t a, d; \
- __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d)); \
- val = ((uint64_t)a) | (((uint64_t)d) << 32); \
-}
-#else
-#if (defined(__ia64) && defined(__GNUC__) )
-#define get_clockticks(val) \
-{ \
- __asm__ __volatile__ ("mov %0=ar.itc" : "=r" (val)); \
-}
-#else
-#if (defined(__ia64) && defined(__hpux))
-#include <machine/sys/inline.h>
-#define get_clockticks(val) \
-{ \
- val = _Asm_mov_from_ar (_AREG_ITC); \
-}
-#else
-// POWER PC
-#if (defined(__GNUC__) && (defined(__powerpc__) || (defined(__ppc__))))
-#define get_clockticks(val) \
-{ \
- uint32_t tbu0, tbu1, tbl; \
- do \
- { \
- __asm__ __volatile__ ("mftbu %0" : "=r" (tbu0)); \
- __asm__ __volatile__ ("mftb %0" : "=r" (tbl)); \
- __asm__ __volatile__ ("mftbu %0" : "=r" (tbu1)); \
- } while (tbu0 != tbu1); \
- val = ((uint64_t)tbl) | (((uint64_t)tbu0) << 32); \
-}
-#else
-// SPARC
-#ifdef SPARCV9
-#ifdef _LP64
-#define get_clockticks(val) \
-{ \
- __asm__ __volatile__ ("rd %%tick, %0" : "=r" (val)); \
-}
-#else
-#define get_clockticks(val) \
-{ \
- uint32_t a, b; \
- __asm__ __volatile__ ("rd %%tick, %0\n" \
- "srlx %0, 32, %1" \
- : "=r" (a), "=r" (b)); \
- val = ((uint64_t)a) | (((uint64_t)b) << 32); \
-}
-#endif // _LP64
-#else
-#define get_clockticks(val)
-#endif // SPARCV9
-#endif // __GNUC__ && __powerpc__ || __ppc__
-#endif // __ia64 && __hpux
-#endif // __ia64 && __GNUC__
-#endif // __i386 || __amd64 || __x86_64__
-
-inline double get_ticks_per_usec()
-{
- uint64_t start = 0, end = 0;
- get_clockticks(start);
-
- sleep(1);
- get_clockticks(end);
-
- return (double)(end-start)/1e6;
-}
-
-#endif
-
namespace t_stopwatch
{
-struct Clock : public ClockTraits<hr_clock>
+struct Clock : public ClockTraits<SnortClock>
{
static time_point now()
{ return time; }
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// tsc_clock.cc author Russ Combs <rucombs@cisco.com>
+
+#include "tsc_clock.h"
+#include <time.h>
+
+long clock_scale()
+{
+ static long tpus = 0; // ticks / usec
+
+ if ( !tpus )
+ {
+ struct timespec one_sec = { 1, 0 };
+ uint64_t start = TscClock::counter();
+ nanosleep(&one_sec, nullptr);
+ uint64_t end = TscClock::counter();
+ tpus = (long)((end - start)/1e6);
+ }
+ return tpus;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// tsc_clock.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef TSC_CLOCK_H
+#define TSC_CLOCK_H
+
+// the STL chrono clocks are kinda heavy so we use the time stamp counter
+// where available (x86 with rdtsc support). this wasn't always a good
+// choice on multi-core systems but most now have rdtscp, constant_tsc,
+// tsc_reliable, and nonstop_tsc. note that we don't worry about exact
+// instruction sequencing.
+//
+// references:
+// http://stackoverflow.com/questions/275004/timer-function-to-provide-time-in-nano-seconds-using-c
+// http://stackoverflow.com/questions/7935518/is-clock-gettime-adequate-for-submicrosecond-timing
+//
+// this clock stores ticks, not actual time values. use ticks during runtime
+// convert from/to usecs at startup/shutdown. see clock_defs.h.
+
+#include <chrono>
+
+struct TscClock
+{
+ // this has to be const so we use a nice round number and scale it later
+ typedef std::ratio<1, 1000000> period;
+
+ typedef uint64_t rep;
+ typedef std::chrono::duration<rep, period> duration;
+ typedef std::chrono::time_point<TscClock> time_point;
+
+ static const bool is_steady = true;
+
+ static uint64_t counter()
+ {
+ uint32_t lo, hi;
+ asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
+ return ((uint64_t)hi << 32) | lo;
+ }
+
+ static time_point now() noexcept
+ {
+ return time_point(duration(counter()));
+ }
+};
+
+long clock_scale();
+
+#endif
+