diff --git a/src/iosource/pktsrc/PktSrc.cc b/src/iosource/pktsrc/PktSrc.cc index c608f5267f..66d18638b8 100644 --- a/src/iosource/pktsrc/PktSrc.cc +++ b/src/iosource/pktsrc/PktSrc.cc @@ -35,7 +35,7 @@ const std::string& PktSrc::Path() const const char* PktSrc::ErrorMsg() const { - return errbuf.c_str(); + return errbuf.size() ? errbuf.c_str() : 0; } int PktSrc::LinkType() const diff --git a/src/iosource/pktsrc/netmap/CMakeLists.txt b/src/iosource/pktsrc/netmap/CMakeLists.txt new file mode 100644 index 0000000000..a8a8a78a16 --- /dev/null +++ b/src/iosource/pktsrc/netmap/CMakeLists.txt @@ -0,0 +1,12 @@ + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}) + +find_package(Netmap) + +if ( NETMAP_FOUND ) + include(BroPlugin) + include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${NETMAP_INCLUDE_DIR}/sys) + bro_plugin_begin(Bro Netmap) + bro_plugin_cc(Source.cc Plugin.cc) + bro_plugin_end() +endif () diff --git a/src/iosource/pktsrc/netmap/FindNetmap.cmake b/src/iosource/pktsrc/netmap/FindNetmap.cmake new file mode 100644 index 0000000000..a04da2a6a0 --- /dev/null +++ b/src/iosource/pktsrc/netmap/FindNetmap.cmake @@ -0,0 +1,33 @@ +# - Try to find netmap includes. +# +# +# Variables used by this module, they can change the default behaviour and need +# to be set before calling find_package: +# +# NETMAP_ROOT_DIR Set this variable to the root installation of +# netmap if the module has problems finding the +# proper installation path. +# +# Variables defined by this module: +# +# NETMAP_FOUND System has netmap API files. +# NETMAP_INCLUDE_DIR The netmap include directory. + +find_path(NETMAP_ROOT_DIR + NAMES sys/net/netmap_user.h +) + +find_path(NETMAP_INCLUDE_DIR + NAMES sys/net/netmap_user.h + HINTS ${NETMAP_ROOT_DIR} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Netmap DEFAULT_MSG + NETMAP_INCLUDE_DIR +) + +mark_as_advanced( + NETMAP_ROOT_DIR + NETMAP_INCLUDE_DIR +) diff --git a/src/iosource/pktsrc/netmap/Plugin.cc b/src/iosource/pktsrc/netmap/Plugin.cc new file mode 100644 index 0000000000..05b4434e16 --- /dev/null +++ b/src/iosource/pktsrc/netmap/Plugin.cc @@ -0,0 +1,26 @@ +// See the file in the main distribution directory for copyright. + +#include "plugin/Plugin.h" + +#include "Source.h" + +namespace plugin { +namespace Bro_Netmap { + +class Plugin : public plugin::Plugin { +public: + plugin::Configuration Configure() + { + AddComponent(new ::iosource::pktsrc::SourceComponent("NetmapReader", "netmap", ::iosource::pktsrc::SourceComponent::LIVE, ::iosource::pktsrc::NetmapSource::InstantiateNetmap)); + AddComponent(new ::iosource::pktsrc::SourceComponent("NetmapReader", "vale", ::iosource::pktsrc::SourceComponent::LIVE, ::iosource::pktsrc::NetmapSource::InstantiateVale)); + + plugin::Configuration config; + config.name = "Bro::Netmap"; + config.description = "Packet aquisition via netmap"; + return config; + } +} plugin; + +} +} + diff --git a/src/iosource/pktsrc/netmap/Source.cc b/src/iosource/pktsrc/netmap/Source.cc new file mode 100644 index 0000000000..b0569a5a0c --- /dev/null +++ b/src/iosource/pktsrc/netmap/Source.cc @@ -0,0 +1,127 @@ + +#include + +#include "config.h" + +#include "Source.h" + +using namespace iosource::pktsrc; + +NetmapSource::~NetmapSource() + { + Close(); + } + +NetmapSource::NetmapSource(const std::string& path, const std::string& filter, bool is_live, const std::string& arg_kind) + { + if ( ! is_live ) + Error("netmap source does not support offline input"); + + kind = arg_kind; + props.path = path; + props.filter = filter; + last_data = 0; + } + +void NetmapSource::Close() + { + if ( ! nd ) + return; + + nm_close(nd); + nd = 0; + last_data = 0; + + Closed(); + } + +void NetmapSource::Open() + { + std::string iface = kind + ":" + props.path; + nd = nm_open(iface.c_str(), getenv("NETMAP_RING_ID"), 0, 0); + + if ( ! nd ) + { + Error(errno ? strerror(errno) : "invalid interface"); + return; + } + + props.selectable_fd = NETMAP_FD(nd); + props.is_live = true; + props.link_type = DLT_EN10MB; + props.hdr_size = GetLinkHeaderSize(props.link_type); + assert(props.hdr_size >= 0); + + Info(fmt("netmap listening on %s\n", props.path.c_str())); + + Opened(props); + } + +int NetmapSource::ExtractNextPacket(Packet* pkt) + { + nm_hdr_t hdr; + const u_char* data = nm_nextpkt(nd, &hdr); + + if ( ! data ) + // Source has gone dry. + return 0; + + current_hdr.ts = hdr.ts; + current_hdr.caplen = hdr.caplen; + current_hdr.len = hdr.len; + + pkt->ts = current_hdr.ts.tv_sec + double(current_hdr.ts.tv_usec) / 1e6; + pkt->hdr = ¤t_hdr; + pkt->data = last_data = data; + + if ( current_hdr.len == 0 || current_hdr.caplen == 0 ) + { + Weird("empty_netmap_header", pkt); + return 0; + } + + last_hdr = current_hdr; + last_data = data; + ++stats.received; + return 1; + } + +void NetmapSource::DoneWithPacket(Packet* pkt) + { + // Nothing to do. + } + +void NetmapSource::Statistics(Stats* s) + { + if ( ! nd ) + { + s->received = s->link = s->dropped = 0; + return; + } + + s->received = stats.received; + + // TODO: Seems these counter's aren't actually set? + s->link = nd->st.ps_recv; + s->dropped = nd->st.ps_drop + nd->st.ps_ifdrop; + } + +bool NetmapSource::GetCurrentPacket(const pcap_pkthdr** hdr, const u_char** pkt) + { + if ( ! last_data ) + return false; + + *hdr = &last_hdr; + *pkt = last_data; + return true; + } + +iosource::PktSrc* NetmapSource::InstantiateNetmap(const std::string& path, const std::string& filter, bool is_live) + { + return new NetmapSource(path, filter, is_live, "netmap"); + } + +iosource::PktSrc* NetmapSource::InstantiateVale(const std::string& path, const std::string& filter, bool is_live) + { + return new NetmapSource(path, filter, is_live, "value"); + } diff --git a/src/iosource/pktsrc/netmap/Source.h b/src/iosource/pktsrc/netmap/Source.h new file mode 100644 index 0000000000..ff17fe792c --- /dev/null +++ b/src/iosource/pktsrc/netmap/Source.h @@ -0,0 +1,48 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#ifndef IOSOURCE_PKTSRC_NETMAP_SOURCE_H +#define IOSOURCE_PKTSRC_NETMAP_SOURCE_H + +extern "C" { +#define NETMAP_WITH_LIBS +#include +} + +#include "../PktSrc.h" + +namespace iosource { +namespace pktsrc { + +class NetmapSource : public iosource::PktSrc { +public: + // XXX + NetmapSource(const std::string& path, const std::string& filter, bool is_live, const std::string& kind); + virtual ~NetmapSource(); + + static PktSrc* InstantiateNetmap(const std::string& path, const std::string& filter, bool is_live); + static PktSrc* InstantiateVale(const std::string& path, const std::string& filter, bool is_live); + +protected: + // PktSrc interface. + virtual void Open(); + virtual void Close(); + virtual int ExtractNextPacket(Packet* pkt); + virtual void DoneWithPacket(Packet* pkt); + virtual void Statistics(Stats* stats); + virtual bool GetCurrentPacket(const pcap_pkthdr** hdr, const u_char** pkt); + +private: + std::string kind; + Properties props; + Stats stats; + + nm_desc_t *nd; + pcap_pkthdr current_hdr; + pcap_pkthdr last_hdr; + const u_char* last_data; +}; + +} +} + +#endif