Skip to content

Commit

Permalink
Merge pull request NetSys#816 from NetSys/gatehook
Browse files Browse the repository at this point in the history
Add/update CLI commands for gatehook
  • Loading branch information
chris3torek authored Jul 20, 2018
2 parents 00daad1 + 2160ed3 commit 52d08df
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 27 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ core/extra.mk
core/extra.dpdk.mk
core/kmod/.cache.mk
*.retry
.mypy_cache
*.cache.mk

# Vagrant stores temporary files in env/.vagrant
env/.vagrant
Expand Down
77 changes: 70 additions & 7 deletions bessctl/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,22 @@ def get_var_attrs(cli, var_token, partial_word):
var_type = 'gate'
var_desc = 'input gate of a module (default 0)'

elif var_token == 'GATEHOOKCLASS':
var_type = 'name'
var_desc = 'name of a gatehook class'
try:
var_candidates = cli.bess.list_gatehook_classes().names
except:
pass

elif var_token == 'GATEHOOKCLASS...':
var_type = 'name+'
var_desc = 'one or more gatehook class names'
try:
var_candidates = cli.bess.list_gatehook_classes().names
except:
pass

elif var_token == '[ENV_VARS...]':
var_type = 'map'
var_desc = 'Environmental variables for configuration'
Expand Down Expand Up @@ -1447,27 +1463,29 @@ def _show_module(cli, module_name):
for gate in info.igates:
track_str = 'batches N/A packets N/A'
try:
track_str = 'batches %-16d packets %-16d' % (gate.cnt,
track_str = 'batches %-11d packets %-12d' % (gate.cnt,
gate.pkts)
except:
pass
cli.fout.write(' %5d: %s %s\n' %
cli.fout.write(' %3d: %s %s\t%s\n' %
(gate.igate, track_str,
', '.join('%s:%d ->' % (g.name, g.ogate)
for g in gate.ogates)))
for g in gate.ogates),
', '.join(gate.hook_name)))

if len(info.ogates) > 0:
cli.fout.write(' Output gates:\n')
for gate in info.ogates:
track_str = 'batches N/A packets N/A'
try:
track_str = 'batches %-16d packets %-16d' % (gate.cnt,
track_str = 'batches %-11d packets %-12d' % (gate.cnt,
gate.pkts)
except:
pass
cli.fout.write(
' %5d: %s -> %d:%s\n' %
(gate.ogate, track_str, gate.igate, gate.name))
' %3d: %s -> %d:%s\t%s\n' %
(gate.ogate, track_str, gate.igate, gate.name,
', '.join(gate.hook_name)))

if hasattr(info, 'dump'):
dump_str = pprint.pformat(info.dump, width=74)
Expand Down Expand Up @@ -1521,6 +1539,51 @@ def show_mclass_list(cli, cls_names):
_show_mclass(cli, cls_name, True)


@cmd('show gatehook', 'Show the status of all gatehook')
def show_gatehook_all(cli):
gatehooks = cli.bess.list_gatehooks().hooks

if not gatehooks:
raise cli.CommandError('There is no active gatehook to show.')

for gatehook in gatehooks:
if gatehook.HasField('igate'):
cli.fout.write('%-16s %d:%s\n' % (gatehook.hook_name, gatehook.igate,
gatehook.module_name))
else:
cli.fout.write('%-16s %s:%d\n' % (gatehook.hook_name,
gatehook.module_name, gatehook.ogate))


def _show_gatehook_class(cli, cls_name, detail):
info = cli.bess.get_gatehook_class_info(cls_name)
cli.fout.write('%-16s %s\n' % (info.name, info.help))

if detail:
if len(info.cmds) > 0:
cli.fout.write('\t\t commands: %s\n' %
(', '.join(map(lambda cmd, msg: "%s(%s)"
% (cmd, msg),
info.cmds,
info.cmd_args))))
else:
cli.fout.write('\t\t (no commands)\n')


@cmd('show gatehookclass', 'Show all gatehook classes')
def show_gatahook_class_all(cli):
gatehook_classes = cli.bess.list_gatehook_classes().names
for cls_name in gatehook_classes:
_show_gatehook_class(cli, cls_name, False)


@cmd('show gatehookclass GATEHOOKCLASS...',
'Show the details of specified gate classes')
def show_gatehook_class_list(cli, cls_names):
for cls_name in cls_names:
_show_gatehook_class(cli, cls_name, True)


@cmd('import plugin PLUGIN_FILE', 'Import the specified plugin (*.so)')
def import_plugin(cli, plugin):
cli.bess.pause_all()
Expand Down Expand Up @@ -1937,7 +2000,7 @@ def track_module_bits(cli, flag, module_name, direction, gate):
@cmd('track reset MODULE DIRECTION GATE',
'Reset counts of packets, batches, and bits on specified gate')
def track_reset(cli, module_name, direction, gate):
cli.bess.run_gate_command('track', module_name, direction, gate, 'reset',
cli.bess.run_gate_command('Track', module_name, direction, gate, 'reset',
'EmptyArg', {})


Expand Down
48 changes: 48 additions & 0 deletions core/bessctl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ static int collect_igates(Module* m, GetModuleInfoResponse* response) {
ogate->set_ogate(og->gate_idx());
ogate->set_name(og->module()->name());
}

for (const auto& hook : g->hooks()) {
igate->add_hook_name(hook->name());
}
}

return 0;
Expand All @@ -218,6 +222,10 @@ static int collect_ogates(Module* m, GetModuleInfoResponse* response) {
}
ogate->set_name(g->igate()->module()->name());
ogate->set_igate(g->igate()->gate_idx());

for (const auto& hook : g->hooks()) {
ogate->add_hook_name(hook->name());
}
}

return 0;
Expand Down Expand Up @@ -1367,6 +1375,46 @@ class BESSControlImpl final : public BESSControl::Service {
return Status::OK;
}

Status ListGateHookClass(ServerContext*, const EmptyRequest*,
ListGateHookClassResponse* response) override {
std::lock_guard<std::recursive_mutex> lock(mutex_);

for (const auto& pair : bess::GateHookFactory::all_gate_hook_factories()) {
const auto& factory = pair.second;
response->add_names(factory.hook_name());
}
return Status::OK;
}

Status GetGateHookClassInfo(ServerContext*,
const GetGateHookClassInfoRequest* request,
GetGateHookClassInfoResponse* response) override {
std::lock_guard<std::recursive_mutex> lock(mutex_);

VLOG(1) << "GetGateHookClassInfo from client:" << std::endl
<< request->DebugString();
if (!request->name().length()) {
return return_with_error(response, EINVAL,
"Argument must be a name in str");
}

const std::string& cls_name = request->name();
const auto& it = bess::GateHookFactory::all_gate_hook_factories().find(cls_name);
if (it == bess::GateHookFactory::all_gate_hook_factories().end()) {
return return_with_error(response, ENOENT, "No gatehook class '%s' found",
cls_name.c_str());
}
const bess::GateHookFactory* cls = &it->second;

response->set_name(cls->hook_name());
response->set_help(cls->help_text());
for (const auto& cmd : cls->cmds()) {
response->add_cmds(cmd.first);
response->add_cmd_args(cmd.second);
}
return Status::OK;
}

Status ListGateHooks(ServerContext*, const EmptyRequest*,
ListGateHooksResponse* response) override {
std::lock_guard<std::recursive_mutex> lock(mutex_);
Expand Down
6 changes: 4 additions & 2 deletions core/gate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ const GateHookCommands GateHook::cmds;
bool GateHookFactory::RegisterGateHook(GateHook::constructor_t constructor,
const GateHookCommands &cmds,
GateHook::init_func_t init_func,
const std::string &hook_name) {
const std::string &hook_name,
const std::string &help_text) {
return all_gate_hook_factories_holder()
.emplace(std::piecewise_construct, std::forward_as_tuple(hook_name),
std::forward_as_tuple(constructor, cmds, init_func, hook_name))
std::forward_as_tuple(constructor, cmds, init_func, hook_name,
help_text))
.second;
}

Expand Down
24 changes: 19 additions & 5 deletions core/gate.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,23 +119,35 @@ class GateHookFactory {
public:
GateHookFactory(GateHook::constructor_t constructor,
const GateHookCommands &cmds, GateHook::init_func_t init_func,
const std::string &hook_name)
const std::string &hook_name, const std::string &help_text)
: hook_constructor_(constructor),
cmds_(cmds),
hook_init_func_(init_func),
hook_name_(hook_name) {}
hook_name_(hook_name),
help_text_(help_text){}

static bool RegisterGateHook(GateHook::constructor_t constructor,
const GateHookCommands &cmds,
GateHook::init_func_t init_func,
const std::string &hook_name);
const std::string &hook_name,
const std::string &help_text);

static std::map<std::string, GateHookFactory> &all_gate_hook_factories_holder(
bool reset = false);

static const std::map<std::string, GateHookFactory>
&all_gate_hook_factories();

const std::string &hook_name() const { return hook_name_; }
const std::string &help_text() const { return help_text_; }

const std::vector<std::pair<std::string, std::string>> cmds() const {
std::vector<std::pair<std::string, std::string>> ret;
for (auto &cmd : cmds_)
ret.push_back(std::make_pair(cmd.cmd, cmd.arg_type));
return ret;
}

CommandResponse RunCommand(GateHook *hook, const std::string &user_cmd,
const google::protobuf::Any &arg) const;

Expand All @@ -146,6 +158,7 @@ class GateHookFactory {
const GateHookCommands cmds_;
GateHook::init_func_t hook_init_func_;
std::string hook_name_;
std::string help_text_;
};

inline CommandResponse GateHook::RunCommand(const std::string &cmd,
Expand Down Expand Up @@ -277,9 +290,10 @@ static inline bess::GateHook::init_func_t InitGateHookWithGenericArg(
};
}

#define ADD_GATE_HOOK(_HOOK) \
#define ADD_GATE_HOOK(_HOOK, _HELP) \
bool __gate_hook__##_HOOK = bess::GateHookFactory::RegisterGateHook( \
std::function<bess::GateHook *()>([]() { return new _HOOK(); }), \
_HOOK::cmds, InitGateHookWithGenericArg(&_HOOK::Init), _HOOK::kName);
_HOOK::cmds, InitGateHookWithGenericArg(&_HOOK::Init), _HOOK::kName, \
_HELP);

#endif // BESS_GATE_H_
4 changes: 2 additions & 2 deletions core/gate_hooks/pcapng.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void BytesToHexDump(const void *src, size_t len, char *dst) {

} // namespace

const std::string Pcapng::kName = "pcapng";
const std::string Pcapng::kName = "PcapNg";

Pcapng::Pcapng()
: bess::GateHook(Pcapng::kName, Pcapng::kPriority),
Expand Down Expand Up @@ -247,4 +247,4 @@ void Pcapng::ProcessBatch(const bess::PacketBatch *batch) {
}
}

ADD_GATE_HOOK(Pcapng)
ADD_GATE_HOOK(Pcapng, "metadata-dump-able packet dump")
4 changes: 2 additions & 2 deletions core/gate_hooks/tcpdump.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
#include "../utils/pcap.h"
#include "../utils/time.h"

const std::string Tcpdump::kName = "tcpdump";
const std::string Tcpdump::kName = "TcpDump";

bool TcpdumpOpener::InitFifo(int fd) {
static const struct pcap_hdr hdr = {
Expand Down Expand Up @@ -104,4 +104,4 @@ void Tcpdump::ProcessBatch(const bess::PacketBatch *batch) {
}
}

ADD_GATE_HOOK(Tcpdump)
ADD_GATE_HOOK(Tcpdump, "dump traffic on a network")
4 changes: 2 additions & 2 deletions core/gate_hooks/track.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
// Ethernet overhead in bytes
static const size_t kEthernetOverhead = 24;

const std::string Track::kName = "track";
const std::string Track::kName = "Track";

const GateHookCommands Track::cmds = {{"reset", "EmptyArg",
GATE_HOOK_CMD_FUNC(&Track::CommandReset),
Expand Down Expand Up @@ -74,4 +74,4 @@ void Track::ProcessBatch(const bess::PacketBatch *batch) {
}
}

ADD_GATE_HOOK(Track)
ADD_GATE_HOOK(Track, "count the packets and batches")
25 changes: 22 additions & 3 deletions protobuf/bess_msg.proto
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ message GetModuleInfoResponse {
uint64 pkts = 4; /// # of packets seen
uint64 bytes = 5; /// # of bytes seen
double timestamp = 6; /// The time that cnt/pkts counters were read
repeated string hook_name = 7; /// List of hooks per gate
}
message OGate {
uint64 ogate = 1; /// Output gate ID
Expand All @@ -420,6 +421,7 @@ message GetModuleInfoResponse {
double timestamp = 5; /// The time thatcnt/pkts counters were read
string name = 6; /// Name of the "next" module it connects to
uint64 igate = 7; /// Input gate ID of the "next" module
repeated string hook_name = 8; /// List of hooks per gate
}
message Attribute {
string name = 1; /// Name of per-packet metadata attribute
Expand All @@ -442,7 +444,7 @@ message ConnectModulesRequest {
uint64 ogate = 3; /// m1's output gate ID
uint64 igate = 4; /// m2's input gate ID
/// If true do not attach default hooks at the input/output gate.
/// (Currently, the only default hook is the "track" hook at the ogate)
/// (Currently, the only default hook is the "Track" hook at the ogate)
bool skip_default_hooks = 5;
}

Expand Down Expand Up @@ -490,9 +492,26 @@ message CommandResponse {
// Gate hooks
// -------------------------------------------------------------------------

/// Enable/Disable the "track" hook on a gate (or all gates)
message ListGateHookClassResponse {
Error error = 1;
repeated string names = 2; /// List of gatehook types
}

message GetGateHookClassInfoRequest {
string name = 1; /// Name of gatehook type
}

message GetGateHookClassInfoResponse {
Error error = 1;
string name = 2; /// Name of gatehook type
string help = 3; /// 1=line description of the gatehook type
repeated string cmds = 4; /// List of commands supported by the gatehook
repeated string cmd_args = 5; /// Corresponding Protobuf message types
}

/// Enable/Disable the "Track" hook on a gate (or all gates)
///
/// "track" hook accumulates the number of total packets, batches and bits
/// "Track" hook accumulates the number of total packets, batches and bits
/// passing through a gate. This incurs some amount of CPU overheads. While
/// the cost is very small, remember that the delay adds up at every gate.
///
Expand Down
8 changes: 7 additions & 1 deletion protobuf/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,16 @@ service BESSControl {
// Gate hooks
// -------------------------------------------------------------------------

/// Enumerate all gatehook types available
rpc ListGateHookClass (EmptyRequest) returns (ListGateHookClassResponse) {}

/// Query detailed information of a gatehook type
rpc GetGateHookClassInfo (GetGateHookClassInfoRequest) returns (GetGateHookClassInfoResponse) {}

/// Enable/Disable a gate hook.
rpc ConfigureGateHook (ConfigureGateHookRequest) returns (CommandResponse) {}

/// Enable/Disable a gate hook.
/// Enumerate all gatehook installed
rpc ListGateHooks (EmptyRequest) returns (ListGateHooksResponse) {}

/// Send command to gate hook instance.
Expand Down
Loading

0 comments on commit 52d08df

Please sign in to comment.