#include "capture_module.h"
+#include <filesystem>
#include <lua.hpp>
#include "control/control.h"
#include "main/analyzer_command.h"
+#include "log/messages.h"
#include "profiler/profiler.h"
#include "utils/util.h"
static int enable(lua_State*);
static int disable(lua_State*);
+bool is_path_valid(const std::string& path);
static const Parameter s_capture[] =
{
{ "check_inner_pkt", Parameter::PT_BOOL, nullptr, "true",
"apply filter on inner packet headers" },
+
+ { "capture_path", Parameter::PT_STRING, nullptr, nullptr,
+ "directory path to capture pcaps" },
+
+ { "max_packet_count", Parameter::PT_INT, "0:max32", "1000000",
+ "cap the number of packets per thread" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
{ "check_inner_pkt", Parameter::PT_BOOL, nullptr, "true",
"apply filter on inner packet headers" },
+ { "capture_path", Parameter::PT_STRING, nullptr, nullptr,
+ "directory path to capture pcaps" },
+
+ { "max_packet_count", Parameter::PT_INT, "0:max32", "1000000",
+ "cap the number of packets per thread" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
class PacketCaptureDebug : public AnalyzerCommand
{
public:
- PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci);
+ PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci,
+ const char* p, const unsigned max);
bool execute(Analyzer&, void**) override;
const char* stringify() override { return "PACKET_CAPTURE_DEBUG"; }
private:
int16_t group = -1;
std::string tenants;
bool check_inner_pkt = true;
+ std::string capture_path;
+ unsigned max_packet_count = 0;
};
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
static int enable(lua_State* L)
{
+ ControlConn* ctrlcon = ControlConn::query_from_lua(L);
+ auto log_response = [ctrlcon](const char* response)
+ {
+ if (ctrlcon)
+ ctrlcon->respond("%s", response);
+ else
+ LogMessage("%s", response);
+ };
+
+ std::string path = luaL_optstring(L, 5, "");
+ if ( !path.empty() && !is_path_valid(path) )
+ {
+ log_response("== Capture path invalid\n");
+ return 0;
+ }
+
+ auto max_limit = luaL_optint(L, 6, 0);
+ if ( max_limit < 0)
+ {
+ log_response("== Max packet count invalid\n");
+ return 0;
+ }
main_broadcast_command(new PacketCaptureDebug(luaL_optstring(L, 1, ""),
- luaL_optint(L, 2, 0), luaL_optstring(L, 3, ""), luaL_opt(L, lua_toboolean, 4, true)), ControlConn::query_from_lua(L));
+ luaL_optint(L, 2, 0), luaL_optstring(L, 3, ""), luaL_opt(L, lua_toboolean, 4, true),
+ path.c_str(), max_limit), ctrlcon);
return 0;
}
static int disable(lua_State* L)
{
- main_broadcast_command(new PacketCaptureDebug(nullptr, -1, nullptr, true), ControlConn::query_from_lua(L));
+ main_broadcast_command(new PacketCaptureDebug(nullptr, -1, nullptr, true, nullptr, 0),
+ ControlConn::query_from_lua(L));
return 0;
}
// non-static functions
// -----------------------------------------------------------------------------
-PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci)
+PacketCaptureDebug::PacketCaptureDebug(const char* f, const int16_t g, const char* t, const bool ci, \
+ const char* p, const unsigned max)
{
if (f)
{
enable = true;
tenants = t == nullptr ? "" : t;
check_inner_pkt = ci;
+ capture_path = p;
+ max_packet_count = max;
}
}
bool PacketCaptureDebug::execute(Analyzer&, void**)
{
if (enable)
- packet_capture_enable(filter, group, tenants, check_inner_pkt);
+ packet_capture_enable(filter, group, tenants, check_inner_pkt, capture_path, max_packet_count);
else
packet_capture_disable();
else if ( v.is("check_inner_pkt") )
config.check_inner_pkt = v.get_bool();
+
+ else if ( v.is("capture_path") )
+ {
+ if ( !is_path_valid(v.get_string()) )
+ {
+ return false;
+ }
+ config.capture_path = v.get_string();
+ }
+
+ else if ( v.is("max_packet_count") )
+ config.max_packet_count = v.get_uint32();
return true;
}
PegCount* CaptureModule::get_counts() const
{ return (PegCount*)&cap_count_stats; }
+bool is_path_valid(const std::string& path)
+{
+ if ( !std::filesystem::exists(path) )
+ {
+ WarningMessage("Cannot create pcap at %s; directory does not exist\n", path.c_str());
+ return false;
+ }
+ return true;
+}
#include "framework/inspector.h"
#include "log/messages.h"
+#include "main/thread_config.h"
#include "packet_io/sfdaq.h"
#include "protocols/packet.h"
#include "utils/util.h"
static THREAD_LOCAL pcap_t* pcap = nullptr;
static THREAD_LOCAL pcap_dumper_t* dumper = nullptr;
static THREAD_LOCAL struct bpf_program bpf;
+static THREAD_LOCAL unsigned packet_count = 0;
// -----------------------------------------------------------------------------
// static functions
static bool open_pcap_dumper()
{
string fname;
- get_instance_file(fname, FILE_NAME);
+ if ( config.capture_path.empty() )
+ get_instance_file(fname, FILE_NAME);
+ else
+ {
+ auto file_name = std::string(FILE_NAME);
+ if ( ThreadConfig::get_instance_max() > 1 )
+ file_name.insert(file_name.find(".pcap"),
+ ("_" + std::to_string(get_instance_id()) + \
+ "_" + std::to_string(get_relative_instance_number())));
+ fname = config.capture_path + "/" + file_name;
+ }
pcap = pcap_open_dead(get_dlt(), SNAP_LEN);
dumper = pcap ? pcap_dump_open(pcap, fname.c_str()) : nullptr;
}
// for unit test
-static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "", const bool ci = true)
+static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "",
+ const bool ci = true, const string& path = "", const unsigned max = 0)
{
if ( !config.enabled )
{
config.group = g;
config.check_inner_pkt = ci;
str_to_int_vector(t, ',', config.tenants);
+ config.capture_path = path;
+ config.max_packet_count = max;
}
}
config.group = -1;
config.tenants.clear();
config.check_inner_pkt = true;
+ config.capture_path.clear();
+ config.max_packet_count = 0;
LogMessage("Packet capture disabled\n");
}
// non-static functions
// -----------------------------------------------------------------------------
-void packet_capture_enable(const string& f, const int16_t g, const string& t, const bool ci)
+void packet_capture_enable(const string& f, const int16_t g, const string& t, const bool ci,
+ const string& p, const unsigned max)
{
- _packet_capture_enable(f, g, t, ci);
+ _packet_capture_enable(f, g, t, ci, p, max);
if ( !capture_initialized() )
{
{
ConfigLogger::log_value("filter", config.filter.c_str());
ConfigLogger::log_value("tenants", int_vector_to_str(config.tenants).c_str());
+ ConfigLogger::log_value("capture_path", config.capture_path.c_str());
+ ConfigLogger::log_value("max_packet_count", config.max_packet_count);
}
}
void PacketCapture::write_packet(Packet* p)
{
+ if ( config.max_packet_count )
+ {
+ if ( packet_count >= config.max_packet_count )
+ return;
+
+ packet_count++;
+ }
struct pcap_pkthdr pcaphdr;
pcaphdr.ts = p->pkth->ts;
pcaphdr.caplen = p->pktlen;