@@ -0,0 +1,224 @@
#include "bro-config.h"

#include "Myricom.h"
#include "myricom.bif.h"

using namespace iosource::pktsrc;

MyricomSource::~MyricomSource()
{
Close();
}

MyricomSource::MyricomSource(const std::string& path, bool is_live, const std::string& arg_kind)
{
if ( ! is_live )
Error("Myricom source does not support offline input");

kind = arg_kind;
current_filter = -1;
props.path = path;
props.is_live = is_live;
}

static inline struct timeval snf_timestamp_to_timeval(const int64_t ts_nanosec)
{
struct timeval tv;
long tv_nsec;

if (ts_nanosec == 0)
return (struct timeval) { 0, 0 };

tv.tv_sec = ts_nanosec / _NSEC_PER_SEC;
tv_nsec = (ts_nanosec % _NSEC_PER_SEC);
tv.tv_usec = tv_nsec / 1000;

return tv;
}

void MyricomSource::Open()
{
uint64_t snf_num_rings = BifConst::Myricom::snf_num_rings;
uint64_t snf_ring_size = BifConst::Myricom::snf_ring_size;
const char * snf_rss = reinterpret_cast<const char*>(BifConst::Myricom::snf_rss->Bytes());
const char * snf_flags = reinterpret_cast<const char*>(BifConst::Myricom::snf_flags->Bytes());
snf_link_state snf_link_isup;
snf_timesource_state snf_timesource_active;
std::string ts_local = "Local timesource (no external)";
std::string ts_ext_unsynced = "External Timesource: not synchronized (yet)";
std::string ts_ext_synced = "External Timesource: synchronized";
std::string ts_ext_failed = "External Timesource: NIC failure to connect to source";
std::string ts_arista_active = "Arista switch is sending ptp timestamps";
std::string iface = props.path;
struct snf_ifaddrs *ifaddrs = NULL, *ifa;
size_t devlen;
uint32_t portnum = -1;

if ( snf_init(SNF_VERSION_API) != 0) {
Error(errno ? strerror(errno) : "SNF: failed in snf_init");
return;
}

if ( snf_getifaddrs(&ifaddrs) != 0 ) {
Error(errno ? strerror(errno) : "SNF: failed in snf_getifaddrs");
return;
}

devlen = strlen(iface.data()) + 1;
ifa = ifaddrs;
while (ifa != NULL) {
if (!strncmp(iface.data(), ifa->snf_ifa_name, devlen)) {
portnum = ifa->snf_ifa_boardnum;
break;
}
ifa = ifa->snf_ifa_next;
}
snf_freeifaddrs(ifaddrs);

if ( ifa == NULL ) {
Error(errno ? strerror(errno) : "SNF: failed to map the interface to the board numer");
return;
}

if ( snf_open(portnum, snf_num_rings, NULL, snf_ring_size, SNF_F_PSHARED, &snf_handle) != 0 ) {
Error(errno ? strerror(errno) : "SNF: failed in snf_open");
return;
}

if ( snf_get_link_state(snf_handle, &snf_link_isup) != 0 ) {
Error(errno ? strerror(errno) : "SNF: failed in snf_get_link_state");
return;
}

if (snf_link_isup != SNF_LINK_UP) {
Error(errno ? strerror(errno) : "SNF: interface is down");
return;
}

if ( snf_get_timesource_state(snf_handle, &snf_timesource_active) != 0 ) {
Error(errno ? strerror(errno) : "SNF: failed in snf_get_timesource_state");
return;
}

switch(snf_timesource_active) {
case SNF_TIMESOURCE_LOCAL:
printf("SNF: %s\n", ts_local.data());
break;
case SNF_TIMESOURCE_EXT_UNSYNCED:
printf("SNF: %s\n", ts_ext_unsynced.data());
break;
case SNF_TIMESOURCE_EXT_SYNCED:
printf("SNF: %s\n", ts_ext_synced.data());
break;
case SNF_TIMESOURCE_EXT_FAILED:
printf("SNF: %s\n", ts_ext_failed.data());
break;
case SNF_TIMESOURCE_ARISTA_ACTIVE:
printf("SNF: %s\n", ts_arista_active.data());
break;
default:
printf("SNF: I have no idea what the timesource is\n");
}
fflush(stdout);


if ( snf_ring_open(snf_handle, &snf_ring) ) {
Error(errno ? strerror(errno) : "failed in snf_ring_open");
return;
}

if ( snf_start(snf_handle) ) {
Error(errno ? strerror(errno) : "failed in snf_start");
return;
}

props.netmask = 0xffffff00;
props.is_live = true;
props.link_type = DLT_EN10MB; // XXX?

num_discarded = 0;

Opened(props);
}

void MyricomSource::Close()
{
if ( ! snf_ring || ! snf_handle )
return;

snf_ring_close(snf_ring);
snf_close(snf_handle);

snf_handle = NULL;
snf_ring = NULL;

Closed();
}

bool MyricomSource::ExtractNextPacket(Packet* pkt)
{
struct snf_recv_req recv_req;
u_char *data;
int rc;
int timeout_ms = 0;

if ( ! snf_ring )
return false;

while ( true )
{
if ( snf_ring_recv(snf_ring, timeout_ms, &recv_req) != 0 )
return false;

current_hdr.ts = snf_timestamp_to_timeval(recv_req.timestamp);
current_hdr.caplen = recv_req.length;
current_hdr.len = recv_req.length;
data = (unsigned char *) recv_req.pkt_addr;

pkt->Init(props.link_type, &current_hdr.ts, current_hdr.caplen, current_hdr.len, data);

if ( ApplyBPFFilter(current_filter, &current_hdr, data) )
break;

++num_discarded;
}

return true;
}

void MyricomSource::DoneWithPacket()
{
// Nothing to do.
}

bool MyricomSource::PrecompileFilter(int index, const std::string& filter)
{
return PktSrc::PrecompileBPFFilter(index, filter);
}

bool MyricomSource::SetFilter(int index)
{
current_filter = index;
return true;
}

void MyricomSource::Statistics(Stats* s)
{
snf_ring_stats ps;

if ( ! snf_ring || snf_ring_getstats(snf_ring, &ps) != 0)
{
s->received = s->link = s->dropped = 0;
return;
}

s->received = ps.ring_pkt_recv + ps.ring_pkt_overflow;
s->link = ps.nic_pkt_recv;
s->dropped = ps.ring_pkt_overflow;
}

iosource::PktSrc* MyricomSource::InstantiateMyricom(const std::string& path, bool is_live)
{
return new MyricomSource(path, is_live, "myricom");
}

@@ -0,0 +1,67 @@
// See the file "COPYING" in the main distribution directory for copyright.

#ifndef IOSOURCE_PKTSRC_Myricom_SOURCE_H
#define IOSOURCE_PKTSRC_Myricom_SOURCE_H

extern "C" {
#include <stdio.h>
}

#include "iosource/PktSrc.h"

#include "snf.h"
#include <errno.h>

#define SNF_F_PSHARED 0x1
#define _NSEC_PER_SEC 1000000000

namespace iosource {
namespace pktsrc {

class MyricomSource : public iosource::PktSrc {
public:
/**
* Constructor.
*
* path: Name of the interface to open.
*
* is_live: Must be true (the SNF source doesn't support offline operation).
*/
MyricomSource(const std::string& path, bool is_live, const std::string& kind);

/**
* Destructor.
*/
virtual ~MyricomSource();

static PktSrc* InstantiateMyricom(const std::string& path, bool is_live);

protected:
// PktSrc interface.
virtual void Open();
virtual void Close();
virtual bool ExtractNextPacket(Packet* pkt);
virtual void DoneWithPacket();
virtual bool PrecompileFilter(int index, const std::string& filter);
virtual bool SetFilter(int index);
virtual void Statistics(Stats* stats);

private:
Properties props;
std::string kind;

int current_filter;
unsigned int num_discarded;

snf_handle_t snf_handle; /* opaque device handle */
snf_ring_t snf_ring; /* opaque device ring handle */
int snf_timeout;
int snf_boardnum;

struct pcap_pkthdr current_hdr;
};

}
}

#endif
@@ -0,0 +1,18 @@
#include "Plugin.h"
#include "Myricom.h"

namespace plugin { namespace Bro_Myricom { Plugin plugin; } }

using namespace plugin::Bro_Myricom;

plugin::Configuration Plugin::Configure()
{
AddComponent(new ::iosource::PktSrcComponent("MyricomReader", "myricom", ::iosource::PktSrcComponent::LIVE, ::iosource::pktsrc::MyricomSource::InstantiateMyricom));

plugin::Configuration config;
config.name = "Bro::Myricom";
config.description = "Packet acquisition via Myricom SNF v3";
config.version.major = 1;
config.version.minor = 0;
return config;
}
@@ -0,0 +1,21 @@
#ifndef BRO_PLUGIN_BRO_MYRICOM
#define BRO_PLUGIN_BRO_MYRICOM

#include <plugin/Plugin.h>

namespace plugin {
namespace Bro_Myricom {

class Plugin : public ::plugin::Plugin
{
protected:
// Overridden from plugin::Plugin.
virtual plugin::Configuration Configure();
};

extern Plugin plugin;

}
}

#endif
@@ -0,0 +1,6 @@
module Myricom;

const snf_ring_size: count;
const snf_flags: string;
const snf_num_rings: count;
const snf_rss: string;
@@ -0,0 +1,3 @@
Bro::Myricom - Packet acquisition via Myricom (dynamic, version 1.0)
[Packet Source] MyricomReader (interface prefix "myricom"; supports live input)

@@ -0,0 +1,3 @@

test:
@btest
@@ -0,0 +1,21 @@
#! /bin/sh
#
# BTest helper for getting values for Bro-related environment variables.

base=`dirname $0`
bro=`cat ${base}/../../build/CMakeCache.txt | grep BRO_DIST | cut -d = -f 2`

if [ "$1" = "brobase" ]; then
echo ${bro}
elif [ "$1" = "bropath" ]; then
${bro}/build/bro-path-dev
elif [ "$1" = "bro_plugin_path" ]; then
( cd ${base}/../../build && pwd )
elif [ "$1" = "bro_seed_file" ]; then
echo ${bro}/testing/btest/random.seed
elif [ "$1" = "path" ]; then
echo ${bro}/build/src:${bro}/aux/btest:${base}/:${bro}/aux/bro-cut:$PATH
else
echo "usage: `basename $0` <var>" >&2
exit 1
fi
@@ -0,0 +1,19 @@
[btest]
TestDirs = myricom
TmpDir = %(testbase)s/.tmp
BaselineDir = %(testbase)s/Baseline
IgnoreDirs = .svn CVS .tmp
IgnoreFiles = *.tmp *.swp #* *.trace .DS_Store

[environment]
BROBASE=`%(testbase)s/Scripts/get-bro-env brobase`
BROPATH=`%(testbase)s/Scripts/get-bro-env bropath`
BRO_PLUGIN_PATH=`%(testbase)s/Scripts/get-bro-env bro_plugin_path`
BRO_SEED_FILE=`%(testbase)s/Scripts/get-bro-env bro_seed_file`
PATH=`%(testbase)s/Scripts/get-bro-env path`
TZ=UTC
LC_ALL=C
TRACES=%(testbase)s/Traces
TMPDIR=%(testbase)s/.tmp
BRO_TRACES=`%(testbase)s/Scripts/get-bro-env brobase`/testing/btest/Traces
TEST_DIFF_CANONIFIER=`%(testbase)s/Scripts/get-bro-env brobase`/testing/scripts/diff-canonifier
@@ -0,0 +1,2 @@
# @TEST-EXEC: bro -NN Bro::myricom >output
# @TEST-EXEC: btest-diff output