diff --git a/scripts/base/frameworks/openflow/main.bro b/scripts/base/frameworks/openflow/main.bro index 5d6b61a9ec..36992d3fe0 100644 --- a/scripts/base/frameworks/openflow/main.bro +++ b/scripts/base/frameworks/openflow/main.bro @@ -50,6 +50,25 @@ export { ## msg: Message to describe the event. global flow_mod_failure: event(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. + ## + ## match: The ofp_match record which was used to create the flow. + ## + ## cookie: The cookie that was specified when creating the flow. + ## + ## priority: The priority that was specified when creating the flow. + ## + ## reason: The reason for flow removal (OFPRR_*) + ## + ## duration_sec: duration of the flow in seconds + ## + ## 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); + ## Convert a conn_id record into an ofp_match record that can be used to ## create match objects for OpenFlow. ## diff --git a/scripts/base/frameworks/openflow/plugins/broker.bro b/scripts/base/frameworks/openflow/plugins/broker.bro index 5af30fdf48..3b721ad5a0 100644 --- a/scripts/base/frameworks/openflow/plugins/broker.bro +++ b/scripts/base/frameworks/openflow/plugins/broker.bro @@ -63,6 +63,6 @@ function broker_new(host: addr, host_port: port, topic: string, dpid: count): Op BrokerComm::subscribe_to_events(topic); # openflow success and failure events are directly sent back via the other plugin via broker. return [$state=[$broker_host=host, $broker_port=host_port, $broker_dpid=dpid, $broker_topic=topic, $_plugin=OpenFlow::BROKER], - $flow_mod=broker_flow_mod_fun, $flow_clear=broker_flow_clear_fun, $describe=broker_describe]; + $flow_mod=broker_flow_mod_fun, $flow_clear=broker_flow_clear_fun, $describe=broker_describe, $supports_flow_removed=T]; } diff --git a/scripts/base/frameworks/openflow/plugins/log.bro b/scripts/base/frameworks/openflow/plugins/log.bro index 5493bed5c7..a7009e474a 100644 --- a/scripts/base/frameworks/openflow/plugins/log.bro +++ b/scripts/base/frameworks/openflow/plugins/log.bro @@ -68,5 +68,5 @@ function log_describe(state: ControllerState): string function log_new(dpid: count, success_event: bool &default=T): OpenFlow::Controller { return [$state=[$log_dpid=dpid, $log_success_event=success_event, $_plugin=OpenFlow::LOG], - $flow_mod=log_flow_mod, $flow_clear=ryu_flow_clear, $describe=log_describe]; + $flow_mod=log_flow_mod, $flow_clear=ryu_flow_clear, $describe=log_describe, $supports_flow_removed=F]; } diff --git a/scripts/base/frameworks/openflow/plugins/ryu.bro b/scripts/base/frameworks/openflow/plugins/ryu.bro index f92c80ec08..490d10ac07 100644 --- a/scripts/base/frameworks/openflow/plugins/ryu.bro +++ b/scripts/base/frameworks/openflow/plugins/ryu.bro @@ -180,5 +180,5 @@ function ryu_describe(state: ControllerState): string function ryu_new(host: addr, host_port: count, dpid: count): OpenFlow::Controller { return [$state=[$ryu_host=host, $ryu_port=host_port, $ryu_dpid=dpid, $_plugin=OpenFlow::RYU], - $flow_mod=ryu_flow_mod, $flow_clear=ryu_flow_clear, $describe=ryu_describe]; + $flow_mod=ryu_flow_mod, $flow_clear=ryu_flow_clear, $describe=ryu_describe, $supports_flow_removed=F]; } diff --git a/scripts/base/frameworks/openflow/types.bro b/scripts/base/frameworks/openflow/types.bro index 0071b758ca..e3bc32ee84 100644 --- a/scripts/base/frameworks/openflow/types.bro +++ b/scripts/base/frameworks/openflow/types.bro @@ -139,6 +139,8 @@ export { type Controller: record { ## Controller related state. state: ControllerState; + ## Does the controller support the flow_removed event? + supports_flow_removed: bool; ## function that describes the controller. Has to be implemented. describe: function(state: ControllerState): string; ## flow_mod function diff --git a/scripts/base/frameworks/pacf/main.bro b/scripts/base/frameworks/pacf/main.bro index c77edec8ef..ec649b422d 100644 --- a/scripts/base/frameworks/pacf/main.bro +++ b/scripts/base/frameworks/pacf/main.bro @@ -118,11 +118,13 @@ export { ## ## r: The rule now removed. ## + ## i: Additional flow information, if supported by the protocol. + ## ## plugin: The name of the plugin that had the rule in place and now ## removed it. ## ## msg: An optional informational message by the plugin. - global rule_timeout: event(r: Rule, p: PluginState); + global rule_timeout: event(r: Rule, i: FlowInfo, p: PluginState); ## Reports an error when operating on a rule. ## @@ -428,7 +430,7 @@ event rule_expire(r: Rule, p: PluginState) # Remove already. return; - event rule_timeout(r, p); + event rule_timeout(r, FlowInfo(), p); remove_rule(r$id); } @@ -448,7 +450,7 @@ event rule_removed(r: Rule, p: PluginState, msg: string &default="") log_rule(r, "REMOVE", SUCCEEDED, p); } -event rule_timeout(r: Rule, p: PluginState) +event rule_timeout(r: Rule, i: FlowInfo, p: PluginState) { delete rules[r$id]; log_rule(r, "EXPIRE", TIMEOUT, p); diff --git a/scripts/base/frameworks/pacf/plugins/openflow.bro b/scripts/base/frameworks/pacf/plugins/openflow.bro index b567575683..5349a1c1e4 100644 --- a/scripts/base/frameworks/pacf/plugins/openflow.bro +++ b/scripts/base/frameworks/pacf/plugins/openflow.bro @@ -30,13 +30,18 @@ export { ## the time interval after which an openflow message is considered to be timed out ## and we delete it from our internal tracking. - const openflow_timeout = 20secs &redef; + const openflow_message_timeout = 20secs &redef; + + ## the time interval after we consider a flow timed out. This should be fairly high (or + ## even disabled) if you expect a lot of long flows. However, one also will have state + ## buildup for quite a while if keeping this around... + const openflow_flow_timeout = 24hrs &redef; ## Instantiates an openflow plugin for the PACF framework. global create_openflow: function(controller: OpenFlow::Controller, config: OfConfig &default=[]) : PluginState; } -global of_messages: table[count, OpenFlow::ofp_flow_mod_command] of OfTable &create_expire=openflow_timeout +global of_messages: table[count, OpenFlow::ofp_flow_mod_command] of OfTable &create_expire=openflow_message_timeout &expire_func=function(t: table[count, OpenFlow::ofp_flow_mod_command] of OfTable, idx: any): interval { local rid: count; @@ -49,6 +54,8 @@ global of_messages: table[count, OpenFlow::ofp_flow_mod_command] of OfTable &cre return 0secs; }; +global of_flows: table[count] of OfTable &create_expire=openflow_flow_timeout; + function openflow_name(p: PluginState) : string { return fmt("Openflow - %s", p$of_controller$describe(p$of_controller$state)); @@ -301,6 +308,9 @@ event OpenFlow::flow_mod_success(match: OpenFlow::ofp_match, flow_mod: OpenFlow: local p = of_messages[id,flow_mod$command]$p; delete of_messages[id,flow_mod$command]; + if ( p$of_controller$supports_flow_removed ) + of_flows[id] = OfTable($p=p, $r=r); + if ( flow_mod$command == OpenFlow::OFPFC_ADD ) event Pacf::rule_added(r, p, msg); else if ( flow_mod$command == OpenFlow::OFPFC_DELETE || flow_mod$command == OpenFlow::OFPFC_DELETE_STRICT ) @@ -320,6 +330,18 @@ event OpenFlow::flow_mod_failure(match: OpenFlow::ofp_match, flow_mod: OpenFlow: event Pacf::rule_error(r, p, msg); } +event OpenFlow::flow_removed(match: OpenFlow::ofp_match, cookie: count, priority: count, reason: count, duration_sec: count, idle_timeout: count, packet_count: count, byte_count: count) + { + local id = OpenFlow::get_cookie_uid(cookie); + if ( id !in of_flows ) + return; + + local r = of_flows[id]$r; + local p = of_flows[id]$p; + + event Pacf::rule_timeout(r, FlowInfo($duration=double_to_interval(duration_sec+0.0), $packet_count=packet_count, $byte_count=byte_count), p); + } + global openflow_plugin = Plugin( $name=openflow_name, $can_expire = T, diff --git a/scripts/base/frameworks/pacf/types.bro b/scripts/base/frameworks/pacf/types.bro index 6166a63dc6..ac8bb06a35 100644 --- a/scripts/base/frameworks/pacf/types.bro +++ b/scripts/base/frameworks/pacf/types.bro @@ -105,6 +105,16 @@ export { id: count &default=0; ##< Internally determined unique ID for this rule. Will be set when added. }; + ## Information of a flow that can be provided by switches when the flow times out. + ## Currently this is heavily influenced by the data that OpenFlow returns by default. + ## That being said - their design makes sense and this is probably the data one + ## can expect to be available. + type FlowInfo: record { + duration: interval &optional; ##< total duration of the rule + packet_count: count &optional; ##< number of packets exchanged over connections matched by the rule + byte_count: count &optional; ##< total bytes exchanged over connections matched by the rule + }; + ## Type of notifications that the framework supports. Each type lists the ## :bro:id:`Notification` argument(s) it uses, if any. ##