Prototype of a netmap packet source.

TODO: Add userland BPF filtering so that our filters work.
This commit is contained in:
Robin Sommer 2014-01-27 15:20:27 -08:00
parent 9a9451af00
commit 462fd68931
6 changed files with 247 additions and 1 deletions

View file

@ -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

View file

@ -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 ()

View file

@ -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
)

View file

@ -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;
}
}

View file

@ -0,0 +1,127 @@
#include <assert.h>
#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 = &current_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");
}

View file

@ -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 <net/netmap_user.h>
}
#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