mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 09:38:19 +00:00
Merge remote-tracking branch 'origin/topic/johanna/netcontrol'
BIT-1550 #merged * origin/topic/johanna/netcontrol: (72 commits) Update baselines and news Move prefixtable back to all IPv6 internal handling. NetControl: Add functions to search for rules affecting IPs/subnets Add check_subnet bif that allows exact membership test for subnet tables. Rewrite internal handling of rules. Add bif that allows searching for all matching subnets in table. Add signaling of succesful initialization of plugins to NetControl. Add rule hooks to the acld plugin. Add new logfiles for shunting and drops to netcontrol Extend NetControl logging and fix bugs. Update OpenFlow API and events. small acld plugin fix Revert "introduce &weaken attribute" Fix crash when printing type of recursive structures. Testcase for crash when a record contains a function referencing a record. Rename Pacf to NetControl fix acld plugin to use address instead of subnet (and add functions for conversion) implement quarantine miscelaneous missing bits and pieces Acld implementation for Pacf - Bro side. ...
This commit is contained in:
commit
2233521de7
107 changed files with 6071 additions and 19 deletions
3
scripts/base/frameworks/openflow/plugins/__load__.bro
Normal file
3
scripts/base/frameworks/openflow/plugins/__load__.bro
Normal file
|
@ -0,0 +1,3 @@
|
|||
@load ./ryu
|
||||
@load ./log
|
||||
@load ./broker
|
95
scripts/base/frameworks/openflow/plugins/broker.bro
Normal file
95
scripts/base/frameworks/openflow/plugins/broker.bro
Normal file
|
@ -0,0 +1,95 @@
|
|||
##! OpenFlow plugin for interfacing to controllers via Broker.
|
||||
|
||||
@load base/frameworks/openflow
|
||||
@load base/frameworks/broker
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
export {
|
||||
redef enum Plugin += {
|
||||
BROKER,
|
||||
};
|
||||
|
||||
## Broker controller constructor.
|
||||
##
|
||||
## host: Controller ip.
|
||||
##
|
||||
## host_port: Controller listen port.
|
||||
##
|
||||
## topic: broker topic to send messages to.
|
||||
##
|
||||
## dpid: OpenFlow switch datapath id.
|
||||
##
|
||||
## Returns: OpenFlow::Controller record
|
||||
global broker_new: function(name: string, host: addr, host_port: port, topic: string, dpid: count): OpenFlow::Controller;
|
||||
|
||||
redef record ControllerState += {
|
||||
## Controller ip.
|
||||
broker_host: addr &optional;
|
||||
## Controller listen port.
|
||||
broker_port: port &optional;
|
||||
## OpenFlow switch datapath id.
|
||||
broker_dpid: count &optional;
|
||||
## Topic to sent events for this controller to
|
||||
broker_topic: string &optional;
|
||||
};
|
||||
|
||||
global broker_flow_mod: event(name: string, dpid: count, match: ofp_match, flow_mod: ofp_flow_mod);
|
||||
global broker_flow_clear: event(name: string, dpid: count);
|
||||
}
|
||||
|
||||
global broker_peers: table[port, string] of Controller;
|
||||
|
||||
function broker_describe(state: ControllerState): string
|
||||
{
|
||||
return fmt("Broker-%s:%d-%d", state$broker_host, state$broker_port, state$broker_dpid);
|
||||
}
|
||||
|
||||
function broker_flow_mod_fun(state: ControllerState, match: ofp_match, flow_mod: OpenFlow::ofp_flow_mod): bool
|
||||
{
|
||||
BrokerComm::event(state$broker_topic, BrokerComm::event_args(broker_flow_mod, state$_name, state$broker_dpid, match, flow_mod));
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function broker_flow_clear_fun(state: OpenFlow::ControllerState): bool
|
||||
{
|
||||
BrokerComm::event(state$broker_topic, BrokerComm::event_args(broker_flow_clear, state$_name, state$broker_dpid));
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function broker_init(state: OpenFlow::ControllerState)
|
||||
{
|
||||
BrokerComm::enable();
|
||||
BrokerComm::connect(cat(state$broker_host), state$broker_port, 1sec);
|
||||
BrokerComm::subscribe_to_events(state$broker_topic); # openflow success and failure events are directly sent back via the other plugin via broker.
|
||||
}
|
||||
|
||||
event BrokerComm::outgoing_connection_established(peer_address: string, peer_port: port, peer_name: string)
|
||||
{
|
||||
if ( [peer_port, peer_address] !in broker_peers )
|
||||
# ok, this one was none of ours...
|
||||
return;
|
||||
|
||||
local p = broker_peers[peer_port, peer_address];
|
||||
controller_init_done(p);
|
||||
delete broker_peers[peer_port, peer_address];
|
||||
}
|
||||
|
||||
# broker controller constructor
|
||||
function broker_new(name: string, host: addr, host_port: port, topic: string, dpid: count): OpenFlow::Controller
|
||||
{
|
||||
local c = OpenFlow::Controller($state=OpenFlow::ControllerState($broker_host=host, $broker_port=host_port, $broker_dpid=dpid, $broker_topic=topic),
|
||||
$flow_mod=broker_flow_mod_fun, $flow_clear=broker_flow_clear_fun, $describe=broker_describe, $supports_flow_removed=T, $init=broker_init);
|
||||
|
||||
register_controller(OpenFlow::BROKER, name, c);
|
||||
|
||||
if ( [host_port, cat(host)] in broker_peers )
|
||||
Reporter::warning(fmt("Peer %s:%s was added to NetControl acld plugin twice.", host, host_port));
|
||||
else
|
||||
broker_peers[host_port, cat(host)] = c;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
76
scripts/base/frameworks/openflow/plugins/log.bro
Normal file
76
scripts/base/frameworks/openflow/plugins/log.bro
Normal file
|
@ -0,0 +1,76 @@
|
|||
##! OpenFlow plugin that outputs flow-modification commands
|
||||
##! to a Bro log file.
|
||||
|
||||
@load base/frameworks/openflow
|
||||
@load base/frameworks/logging
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
export {
|
||||
redef enum Plugin += {
|
||||
OFLOG,
|
||||
};
|
||||
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
## Log controller constructor.
|
||||
##
|
||||
## dpid: OpenFlow switch datapath id.
|
||||
##
|
||||
## success_event: If true, flow_mod_success is raised for each logged line.
|
||||
##
|
||||
## Returns: OpenFlow::Controller record
|
||||
global log_new: function(dpid: count, success_event: bool &default=T): OpenFlow::Controller;
|
||||
|
||||
redef record ControllerState += {
|
||||
## OpenFlow switch datapath id.
|
||||
log_dpid: count &optional;
|
||||
## Raise or do not raise success event
|
||||
log_success_event: bool &optional;
|
||||
};
|
||||
|
||||
## The record type which contains column fields of the OpenFlow log.
|
||||
type Info: record {
|
||||
## Network time
|
||||
ts: time &log;
|
||||
## OpenFlow switch datapath id
|
||||
dpid: count &log;
|
||||
## OpenFlow match fields
|
||||
match: ofp_match &log;
|
||||
## OpenFlow modify flow entry message
|
||||
flow_mod: ofp_flow_mod &log;
|
||||
};
|
||||
|
||||
## Event that can be handled to access the :bro:type:`OpenFlow::Info`
|
||||
## record as it is sent on to the logging framework.
|
||||
global log_openflow: event(rec: Info);
|
||||
}
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(OpenFlow::LOG, [$columns=Info, $ev=log_openflow, $path="openflow"]);
|
||||
}
|
||||
|
||||
function log_flow_mod(state: ControllerState, match: ofp_match, flow_mod: OpenFlow::ofp_flow_mod): bool
|
||||
{
|
||||
Log::write(OpenFlow::LOG, [$ts=network_time(), $dpid=state$log_dpid, $match=match, $flow_mod=flow_mod]);
|
||||
if ( state$log_success_event )
|
||||
event OpenFlow::flow_mod_success(state$_name, match, flow_mod);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function log_describe(state: ControllerState): string
|
||||
{
|
||||
return fmt("Log-%d", state$log_dpid);
|
||||
}
|
||||
|
||||
function log_new(dpid: count, success_event: bool &default=T): OpenFlow::Controller
|
||||
{
|
||||
local c = OpenFlow::Controller($state=OpenFlow::ControllerState($log_dpid=dpid, $log_success_event=success_event),
|
||||
$flow_mod=log_flow_mod, $describe=log_describe, $supports_flow_removed=F);
|
||||
|
||||
register_controller(OpenFlow::OFLOG, cat(dpid), c);
|
||||
|
||||
return c;
|
||||
}
|
190
scripts/base/frameworks/openflow/plugins/ryu.bro
Normal file
190
scripts/base/frameworks/openflow/plugins/ryu.bro
Normal file
|
@ -0,0 +1,190 @@
|
|||
##! OpenFlow plugin for the Ryu controller.
|
||||
|
||||
@load base/frameworks/openflow
|
||||
@load base/utils/active-http
|
||||
@load base/utils/exec
|
||||
@load base/utils/json
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
export {
|
||||
redef enum Plugin += {
|
||||
RYU,
|
||||
};
|
||||
|
||||
## Ryu controller constructor.
|
||||
##
|
||||
## host: Controller ip.
|
||||
##
|
||||
## host_port: Controller listen port.
|
||||
##
|
||||
## dpid: OpenFlow switch datapath id.
|
||||
##
|
||||
## Returns: OpenFlow::Controller record
|
||||
global ryu_new: function(host: addr, host_port: count, dpid: count): OpenFlow::Controller;
|
||||
|
||||
redef record ControllerState += {
|
||||
## Controller ip.
|
||||
ryu_host: addr &optional;
|
||||
## Controller listen port.
|
||||
ryu_port: count &optional;
|
||||
## OpenFlow switch datapath id.
|
||||
ryu_dpid: count &optional;
|
||||
## Enable debug mode - output JSON to stdout; do not perform actions
|
||||
ryu_debug: bool &default=F;
|
||||
};
|
||||
}
|
||||
|
||||
# Ryu ReST API flow_mod URL-path
|
||||
const RYU_FLOWENTRY_PATH = "/stats/flowentry/";
|
||||
# Ryu ReST API flow_stats URL-path
|
||||
#const RYU_FLOWSTATS_PATH = "/stats/flow/";
|
||||
|
||||
# Ryu ReST API action_output type.
|
||||
type ryu_flow_action: record {
|
||||
# Ryu uses strings as its ReST API output action.
|
||||
_type: string;
|
||||
# The output port for type OUTPUT
|
||||
_port: count &optional;
|
||||
};
|
||||
|
||||
# The ReST API documentation can be found at
|
||||
# https://media.readthedocs.org/pdf/ryu/latest/ryu.pdf
|
||||
# Ryu ReST API flow_mod type.
|
||||
type ryu_ofp_flow_mod: record {
|
||||
dpid: count;
|
||||
cookie: count &optional;
|
||||
cookie_mask: count &optional;
|
||||
table_id: count &optional;
|
||||
idle_timeout: count &optional;
|
||||
hard_timeout: count &optional;
|
||||
priority: count &optional;
|
||||
flags: count &optional;
|
||||
match: OpenFlow::ofp_match;
|
||||
actions: vector of ryu_flow_action;
|
||||
out_port: count &optional;
|
||||
out_group: count &optional;
|
||||
};
|
||||
|
||||
# Mapping between ofp flow mod commands and ryu urls
|
||||
const ryu_url: table[ofp_flow_mod_command] of string = {
|
||||
[OFPFC_ADD] = "add",
|
||||
[OFPFC_MODIFY] = "modify",
|
||||
[OFPFC_MODIFY_STRICT] = "modify_strict",
|
||||
[OFPFC_DELETE] = "delete",
|
||||
[OFPFC_DELETE_STRICT] = "delete_strict",
|
||||
};
|
||||
|
||||
# Ryu flow_mod function
|
||||
function ryu_flow_mod(state: OpenFlow::ControllerState, match: ofp_match, flow_mod: OpenFlow::ofp_flow_mod): bool
|
||||
{
|
||||
if ( state$_plugin != RYU )
|
||||
{
|
||||
Reporter::error("Ryu openflow plugin was called with state of non-ryu plugin");
|
||||
return F;
|
||||
}
|
||||
|
||||
# Generate ryu_flow_actions because their type differs (using strings as type).
|
||||
local flow_actions: vector of ryu_flow_action = vector();
|
||||
|
||||
for ( i in flow_mod$actions$out_ports )
|
||||
flow_actions[|flow_actions|] = ryu_flow_action($_type="OUTPUT", $_port=flow_mod$actions$out_ports[i]);
|
||||
|
||||
# Generate our ryu_flow_mod record for the ReST API call.
|
||||
local mod: ryu_ofp_flow_mod = ryu_ofp_flow_mod(
|
||||
$dpid=state$ryu_dpid,
|
||||
$cookie=flow_mod$cookie,
|
||||
$idle_timeout=flow_mod$idle_timeout,
|
||||
$hard_timeout=flow_mod$hard_timeout,
|
||||
$priority=flow_mod$priority,
|
||||
$flags=flow_mod$flags,
|
||||
$match=match,
|
||||
$actions=flow_actions
|
||||
);
|
||||
|
||||
if ( flow_mod?$out_port )
|
||||
mod$out_port = flow_mod$out_port;
|
||||
if ( flow_mod?$out_group )
|
||||
mod$out_group = flow_mod$out_group;
|
||||
|
||||
# Type of the command
|
||||
local command_type: string;
|
||||
|
||||
if ( flow_mod$command in ryu_url )
|
||||
command_type = ryu_url[flow_mod$command];
|
||||
else
|
||||
{
|
||||
Reporter::warning(fmt("The given OpenFlow command type '%s' is not available", cat(flow_mod$command)));
|
||||
return F;
|
||||
}
|
||||
|
||||
local url=cat("http://", cat(state$ryu_host), ":", cat(state$ryu_port), RYU_FLOWENTRY_PATH, command_type);
|
||||
|
||||
if ( state$ryu_debug )
|
||||
{
|
||||
print url;
|
||||
print to_json(mod);
|
||||
event OpenFlow::flow_mod_success(state$_name, match, flow_mod);
|
||||
return T;
|
||||
}
|
||||
|
||||
# Create the ActiveHTTP request and convert the record to a Ryu ReST API JSON string
|
||||
local request: ActiveHTTP::Request = ActiveHTTP::Request(
|
||||
$url=url,
|
||||
$method="POST",
|
||||
$client_data=to_json(mod)
|
||||
);
|
||||
|
||||
# Execute call to Ryu's ReST API
|
||||
when ( local result = ActiveHTTP::request(request) )
|
||||
{
|
||||
if(result$code == 200)
|
||||
event OpenFlow::flow_mod_success(state$_name, match, flow_mod, result$body);
|
||||
else
|
||||
{
|
||||
Reporter::warning(fmt("Flow modification failed with error: %s", result$body));
|
||||
event OpenFlow::flow_mod_failure(state$_name, match, flow_mod, result$body);
|
||||
return F;
|
||||
}
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function ryu_flow_clear(state: OpenFlow::ControllerState): bool
|
||||
{
|
||||
local url=cat("http://", cat(state$ryu_host), ":", cat(state$ryu_port), RYU_FLOWENTRY_PATH, "clear", "/", state$ryu_dpid);
|
||||
|
||||
if ( state$ryu_debug )
|
||||
{
|
||||
print url;
|
||||
return T;
|
||||
}
|
||||
|
||||
local request: ActiveHTTP::Request = ActiveHTTP::Request(
|
||||
$url=url,
|
||||
$method="DELETE"
|
||||
);
|
||||
|
||||
when ( local result = ActiveHTTP::request(request) )
|
||||
{
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function ryu_describe(state: ControllerState): string
|
||||
{
|
||||
return fmt("Ryu-%d-http://%s:%d", state$ryu_dpid, state$ryu_host, state$ryu_port);
|
||||
}
|
||||
|
||||
# Ryu controller constructor
|
||||
function ryu_new(host: addr, host_port: count, dpid: count): OpenFlow::Controller
|
||||
{
|
||||
local c = OpenFlow::Controller($state=OpenFlow::ControllerState($ryu_host=host, $ryu_port=host_port, $ryu_dpid=dpid),
|
||||
$flow_mod=ryu_flow_mod, $flow_clear=ryu_flow_clear, $describe=ryu_describe, $supports_flow_removed=F);
|
||||
|
||||
register_controller(OpenFlow::RYU, cat(host,host_port,dpid), c);
|
||||
|
||||
return c;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue