Update OpenFlow API and events.

Events now generally carry the unique ID of the backend that is given
during initialization; there are a few more functions and other
bugfixes.

A few netcontrol tests are still broken (mostly due to a pcap update in
msater).
This commit is contained in:
Johanna Amann 2016-02-11 13:09:20 -08:00
parent 5e2ec25a38
commit 9f3c0c9bb4
19 changed files with 186 additions and 95 deletions

View file

@ -14,8 +14,6 @@ export {
## Workers need ability to forward commands to manager.
redef Cluster::worker2manager_events += /OpenFlow::cluster_flow_(mod|clear)/;
global name_to_controller: table[string] of Controller;
# the flow_mod function wrapper
function flow_mod(controller: Controller, match: ofp_match, flow_mod: ofp_flow_mod): bool
{
@ -81,14 +79,33 @@ function register_controller(tpe: OpenFlow::Plugin, name: string, controller: Co
if ( Cluster::local_node_type() != Cluster::MANAGER )
return;
if ( controller$state$_name in name_to_controller )
{
Reporter::error("OpenFlow Controller %s was already registered. Ignored duplicate registration");
return;
}
name_to_controller[controller$state$_name] = controller;
if ( controller?$init )
controller$init(controller$state);
register_controller_impl(tpe, name, controller);
}
function unregister_controller(controller: Controller)
{
# we only run the on the manager.
if ( Cluster::local_node_type() != Cluster::MANAGER )
return;
unregister_controller_impl(controller);
}
function lookup_controller(name: string): vector of Controller
{
# we only run the on the manager. Otherwhise we don't have a mapping or state -> return empty
if ( Cluster::local_node_type() != Cluster::MANAGER )
return vector();
# I am not quite sure if we can actually get away with this - in the
# current state, this means that the individual nodes cannot lookup
# a controller by name.
#
# This means that there can be no reactions to things on the actual
# worker nodes - because they cannot look up a name. On the other hand -
# currently we also do not even send the events to the worker nodes (at least
# not if we are using broker). Because of that I am not really feeling that
# badly about it...
return lookup_controller_impl(name);
}

View file

@ -34,26 +34,32 @@ export {
## Event confirming successful modification of a flow rule.
##
## name: The unique name of the OpenFlow controller from which this event originated.
##
## match: The ofp_match record which describes the flow to match.
##
## flow_mod: The openflow flow_mod record which describes the action to take.
##
## msg: An optional informational message by the plugin.
global flow_mod_success: event(match: ofp_match, flow_mod: ofp_flow_mod, msg: string &default="");
global flow_mod_success: event(name: string, match: ofp_match, flow_mod: ofp_flow_mod, msg: string &default="");
## Reports an error while installing a flow Rule.
##
## name: The unique name of the OpenFlow controller from which this event originated.
##
## match: The ofp_match record which describes the flow to match.
##
## flow_mod: The openflow flow_mod record which describes the action to take.
##
## msg: Message to describe the event.
global flow_mod_failure: event(match: ofp_match, flow_mod: ofp_flow_mod, msg: string &default="");
global flow_mod_failure: event(name: string, match: ofp_match, flow_mod: ofp_flow_mod, msg: string &default="");
## Reports that a flow was removed by the switch because of either the hard or the idle timeout.
## This message is only generated by controllers that indicate that they support flow removal
## in supports_flow_removed.
##
## name: The unique name of the OpenFlow controller from which this event originated.
##
## match: The ofp_match record which was used to create the flow.
##
## cookie: The cookie that was specified when creating the flow.
@ -67,7 +73,7 @@ export {
## packet_count: packet count of the flow
##
## byte_count: byte count of the flow
global flow_removed: event(match: ofp_match, cookie: count, priority: count, reason: count, duration_sec: count, idle_timeout: count, packet_count: count, byte_count: count);
global flow_removed: event(name: string, match: ofp_match, cookie: count, priority: count, reason: count, duration_sec: count, idle_timeout: count, packet_count: count, byte_count: count);
## Convert a conn_id record into an ofp_match record that can be used to
## create match objects for OpenFlow.
@ -113,8 +119,25 @@ export {
##
## controller: The controller to register
global register_controller: function(tpe: OpenFlow::Plugin, name: string, controller: Controller);
## Function to unregister a controller instance. This function
## should be called when a specific controller should no longer
## be used.
##
## controller: The controller to unregister
global unregister_controller: function(controller: Controller);
## Function to lookup a controller instance by name
##
## name: unique name of the controller to look up
##
## Returns: one element vector with controller, if found. Empty vector otherwhise.
global lookup_controller: function(name: string): vector of Controller;
}
global name_to_controller: table[string] of Controller;
function match_conn(id: conn_id, reverse: bool &default=F): ofp_match
{
local dl_type = ETH_IPv4;
@ -137,7 +160,7 @@ function match_conn(id: conn_id, reverse: bool &default=F): ofp_match
orig_h = id$resp_h;
orig_p = id$resp_p;
resp_h = id$orig_h;
resp_p = id$resp_p;
resp_p = id$orig_p;
}
if ( is_v6_addr(orig_h) )
@ -203,3 +226,38 @@ function get_cookie_gid(cookie: count): count
return INVALID_COOKIE;
}
# Functions that are called from cluster.bro and non-cluster.bro
function register_controller_impl(tpe: OpenFlow::Plugin, name: string, controller: Controller)
{
if ( controller$state$_name in name_to_controller )
{
Reporter::error("OpenFlow Controller %s was already registered. Ignored duplicate registration");
return;
}
name_to_controller[controller$state$_name] = controller;
if ( controller?$init )
controller$init(controller$state);
}
function unregister_controller_impl(controller: Controller)
{
if ( controller$state$_name in name_to_controller )
delete name_to_controller[controller$state$_name];
else
Reporter::error("OpenFlow Controller %s was not registered in unregister.");
if ( controller?$destroy )
controller$destroy(controller$state);
}
function lookup_controller_impl(name: string): vector of Controller
{
if ( name in name_to_controller )
return vector(name_to_controller[name]);
else
return vector();
}

View file

@ -24,6 +24,15 @@ function register_controller(tpe: OpenFlow::Plugin, name: string, controller: Co
controller$state$_name = cat(tpe, name);
controller$state$_plugin = tpe;
if ( controller?$init )
controller$init(controller$state);
register_controller_impl(tpe, name, controller);
}
function unregister_controller(controller: Controller)
{
unregister_controller_impl(controller);
}
function lookup_controller(name: string): vector of Controller
{
return lookup_controller_impl(name);
}

View file

@ -32,8 +32,8 @@ export {
broker_topic: string &optional;
};
global broker_flow_mod: event(dpid: count, match: ofp_match, flow_mod: ofp_flow_mod);
global broker_flow_clear: event(dpid: count);
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);
}
function broker_describe(state: ControllerState): string
@ -43,14 +43,14 @@ function broker_describe(state: ControllerState): string
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$broker_dpid, match, flow_mod));
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$broker_dpid));
BrokerComm::event(state$broker_topic, BrokerComm::event_args(broker_flow_clear, state$_name, state$broker_dpid));
return T;
}

View file

@ -55,7 +55,7 @@ function log_flow_mod(state: ControllerState, match: ofp_match, flow_mod: OpenFl
{
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(match, flow_mod);
event OpenFlow::flow_mod_success(state$_name, match, flow_mod);
return T;
}

View file

@ -91,7 +91,7 @@ function ryu_flow_mod(state: OpenFlow::ControllerState, match: ofp_match, flow_m
# 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=OpenFlow::generate_cookie(flow_mod$cookie),
$cookie=flow_mod$cookie,
$idle_timeout=flow_mod$idle_timeout,
$hard_timeout=flow_mod$hard_timeout,
$priority=flow_mod$priority,
@ -122,7 +122,7 @@ function ryu_flow_mod(state: OpenFlow::ControllerState, match: ofp_match, flow_m
{
print url;
print to_json(mod);
event OpenFlow::flow_mod_success(match, flow_mod);
event OpenFlow::flow_mod_success(state$_name, match, flow_mod);
return T;
}
@ -137,11 +137,11 @@ function ryu_flow_mod(state: OpenFlow::ControllerState, match: ofp_match, flow_m
when ( local result = ActiveHTTP::request(request) )
{
if(result$code == 200)
event OpenFlow::flow_mod_success(match, flow_mod, result$body);
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(match, flow_mod, result$body);
event OpenFlow::flow_mod_failure(state$_name, match, flow_mod, result$body);
return F;
}
}

View file

@ -108,35 +108,6 @@ export {
actions: ofp_flow_action &default=ofp_flow_action();
} &log;
# Functionality using this is currently not implemented. At all.
# ## Body of reply to OFPST_FLOW request.
# type ofp_flow_stats: record {
# ## ID of table flow came from.
# table_id: count;
# ## Description of fields.
# match: ofp_match;
# ## Time flow has been alive in seconds.
# duration_sec: count;
# ## Time flow has been alive in nanoseconds beyond
# ## duration_sec.
# duration_nsec: count;
# ## Priority of the entry. Only meaningful
# ## when this is not an exact-match entry.
# priority: count;
# ## Number of seconds idle before expiration.
# idle_timeout: count;
# ## Number of seconds before expiration.
# hard_timeout: count;
# ## Opaque controller-issued identifier.
# cookie: count;
# ## Number of packets in flow.
# packet_count: count;
# ## Number of bytes in flow.
# byte_count: count;
# ## Actions
# actions: vector of ofp_action_output;
# };
## Controller record representing an openflow controller
type Controller: record {
## Controller related state.
@ -147,6 +118,8 @@ export {
describe: function(state: ControllerState): string;
## one-time initialization function.
init: function (state: ControllerState) &optional;
## one-time destruction function
destroy: function (state: ControllerState) &optional;
## flow_mod function
flow_mod: function(state: ControllerState, match: ofp_match, flow_mod: ofp_flow_mod): bool &optional;
## flow_clear function