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
13
scripts/base/frameworks/openflow/__load__.bro
Normal file
13
scripts/base/frameworks/openflow/__load__.bro
Normal file
|
@ -0,0 +1,13 @@
|
|||
@load ./consts
|
||||
@load ./types
|
||||
@load ./main
|
||||
@load ./plugins
|
||||
|
||||
# The cluster framework must be loaded first.
|
||||
@load base/frameworks/cluster
|
||||
|
||||
@if ( Cluster::is_enabled() )
|
||||
@load ./cluster
|
||||
@else
|
||||
@load ./non-cluster
|
||||
@endif
|
120
scripts/base/frameworks/openflow/cluster.bro
Normal file
120
scripts/base/frameworks/openflow/cluster.bro
Normal file
|
@ -0,0 +1,120 @@
|
|||
##! Cluster support for the OpenFlow framework.
|
||||
|
||||
@load ./main
|
||||
@load base/frameworks/cluster
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
export {
|
||||
## This is the event used to transport flow_mod messages to the manager.
|
||||
global cluster_flow_mod: event(name: string, match: ofp_match, flow_mod: ofp_flow_mod);
|
||||
|
||||
## This is the event used to transport flow_clear messages to the manager.
|
||||
global cluster_flow_clear: event(name: string);
|
||||
}
|
||||
|
||||
## Workers need ability to forward commands to manager.
|
||||
redef Cluster::worker2manager_events += /OpenFlow::cluster_flow_(mod|clear)/;
|
||||
|
||||
# the flow_mod function wrapper
|
||||
function flow_mod(controller: Controller, match: ofp_match, flow_mod: ofp_flow_mod): bool
|
||||
{
|
||||
if ( ! controller?$flow_mod )
|
||||
return F;
|
||||
|
||||
if ( Cluster::local_node_type() == Cluster::MANAGER )
|
||||
return controller$flow_mod(controller$state, match, flow_mod);
|
||||
else
|
||||
event OpenFlow::cluster_flow_mod(controller$state$_name, match, flow_mod);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function flow_clear(controller: Controller): bool
|
||||
{
|
||||
if ( ! controller?$flow_clear )
|
||||
return F;
|
||||
|
||||
if ( Cluster::local_node_type() == Cluster::MANAGER )
|
||||
return controller$flow_clear(controller$state);
|
||||
else
|
||||
event OpenFlow::cluster_flow_clear(controller$state$_name);
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
@if ( Cluster::local_node_type() == Cluster::MANAGER )
|
||||
event OpenFlow::cluster_flow_mod(name: string, match: ofp_match, flow_mod: ofp_flow_mod)
|
||||
{
|
||||
if ( name !in name_to_controller )
|
||||
{
|
||||
Reporter::error(fmt("OpenFlow controller %s not found in mapping on master", name));
|
||||
return;
|
||||
}
|
||||
|
||||
local c = name_to_controller[name];
|
||||
|
||||
if ( ! c$state$_activated )
|
||||
return;
|
||||
|
||||
if ( c?$flow_mod )
|
||||
c$flow_mod(c$state, match, flow_mod);
|
||||
}
|
||||
|
||||
event OpenFlow::cluster_flow_clear(name: string)
|
||||
{
|
||||
if ( name !in name_to_controller )
|
||||
{
|
||||
Reporter::error(fmt("OpenFlow controller %s not found in mapping on master", name));
|
||||
return;
|
||||
}
|
||||
|
||||
local c = name_to_controller[name];
|
||||
|
||||
if ( ! c$state$_activated )
|
||||
return;
|
||||
|
||||
if ( c?$flow_clear )
|
||||
c$flow_clear(c$state);
|
||||
}
|
||||
@endif
|
||||
|
||||
function register_controller(tpe: OpenFlow::Plugin, name: string, controller: Controller)
|
||||
{
|
||||
controller$state$_name = cat(tpe, name);
|
||||
controller$state$_plugin = tpe;
|
||||
|
||||
# we only run the init functions on the manager.
|
||||
if ( Cluster::local_node_type() != Cluster::MANAGER )
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
229
scripts/base/frameworks/openflow/consts.bro
Normal file
229
scripts/base/frameworks/openflow/consts.bro
Normal file
|
@ -0,0 +1,229 @@
|
|||
##! Constants used by the OpenFlow framework.
|
||||
|
||||
# All types/constants not specific to OpenFlow will be defined here
|
||||
# unitl they somehow get into Bro.
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
# Some cookie specific constants.
|
||||
# first 24 bits
|
||||
const COOKIE_BID_SIZE = 16777216;
|
||||
# start at bit 40 (1 << 40)
|
||||
const COOKIE_BID_START = 1099511627776;
|
||||
# bro specific cookie ID shall have the 42 bit set (1 << 42)
|
||||
const BRO_COOKIE_ID = 4;
|
||||
# 8 bits group identifier
|
||||
const COOKIE_GID_SIZE = 256;
|
||||
# start at bit 32 (1 << 32)
|
||||
const COOKIE_GID_START = 4294967296;
|
||||
# 32 bits unique identifier
|
||||
const COOKIE_UID_SIZE = 4294967296;
|
||||
# start at bit 0 (1 << 0)
|
||||
const COOKIE_UID_START = 0;
|
||||
|
||||
export {
|
||||
# All ethertypes can be found at
|
||||
# http://standards.ieee.org/develop/regauth/ethertype/eth.txt
|
||||
# but are not interesting for us at this point
|
||||
#type ethertype: enum {
|
||||
# Internet protocol version 4
|
||||
const ETH_IPv4 = 0x0800;
|
||||
# Address resolution protocol
|
||||
const ETH_ARP = 0x0806;
|
||||
# Wake on LAN
|
||||
const ETH_WOL = 0x0842;
|
||||
# Reverse address resolution protocol
|
||||
const ETH_RARP = 0x8035;
|
||||
# Appletalk
|
||||
const ETH_APPLETALK = 0x809B;
|
||||
# Appletalk address resolution protocol
|
||||
const ETH_APPLETALK_ARP = 0x80F3;
|
||||
# IEEE 802.1q & IEEE 802.1aq
|
||||
const ETH_VLAN = 0x8100;
|
||||
# Novell IPX old
|
||||
const ETH_IPX_OLD = 0x8137;
|
||||
# Novell IPX
|
||||
const ETH_IPX = 0x8138;
|
||||
# Internet protocol version 6
|
||||
const ETH_IPv6 = 0x86DD;
|
||||
# IEEE 802.3x
|
||||
const ETH_ETHER_FLOW_CONTROL = 0x8808;
|
||||
# Multiprotocol Label Switching unicast
|
||||
const ETH_MPLS_UNICAST = 0x8847;
|
||||
# Multiprotocol Label Switching multicast
|
||||
const ETH_MPLS_MULTICAST = 0x8848;
|
||||
# Point-to-point protocol over Ethernet discovery phase (rfc2516)
|
||||
const ETH_PPPOE_DISCOVERY = 0x8863;
|
||||
# Point-to-point protocol over Ethernet session phase (rfc2516)
|
||||
const ETH_PPPOE_SESSION = 0x8864;
|
||||
# Jumbo frames
|
||||
const ETH_JUMBO_FRAMES = 0x8870;
|
||||
# IEEE 802.1X
|
||||
const ETH_EAP_OVER_LAN = 0x888E;
|
||||
# IEEE 802.1ad & IEEE 802.1aq
|
||||
const ETH_PROVIDER_BRIDING = 0x88A8;
|
||||
# IEEE 802.1ae
|
||||
const ETH_MAC_SECURITY = 0x88E5;
|
||||
# IEEE 802.1ad (QinQ)
|
||||
const ETH_QINQ = 0x9100;
|
||||
#};
|
||||
|
||||
# A list of ip protocol numbers can be found at
|
||||
# http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
|
||||
#type iptype: enum {
|
||||
# IPv6 Hop-by-Hop Option (RFC2460)
|
||||
const IP_HOPOPT = 0x00;
|
||||
# Internet Control Message Protocol (RFC792)
|
||||
const IP_ICMP = 0x01;
|
||||
# Internet Group Management Protocol (RFC1112)
|
||||
const IP_IGMP = 0x02;
|
||||
# Gateway-to-Gateway Protocol (RFC823)
|
||||
const IP_GGP = 0x03;
|
||||
# IP-Within-IP (encapsulation) (RFC2003)
|
||||
const IP_IPIP = 0x04;
|
||||
# Internet Stream Protocol (RFC1190;RFC1819)
|
||||
const IP_ST = 0x05;
|
||||
# Tansmission Control Protocol (RFC793)
|
||||
const IP_TCP = 0x06;
|
||||
# Core-based trees (RFC2189)
|
||||
const IP_CBT = 0x07;
|
||||
# Exterior Gateway Protocol (RFC888)
|
||||
const IP_EGP = 0x08;
|
||||
# Interior Gateway Protocol (any private interior
|
||||
# gateway (used by Cisco for their IGRP))
|
||||
const IP_IGP = 0x09;
|
||||
# User Datagram Protocol (RFC768)
|
||||
const IP_UDP = 0x11;
|
||||
# Reliable Datagram Protocol (RFC908)
|
||||
const IP_RDP = 0x1B;
|
||||
# IPv6 Encapsulation (RFC2473)
|
||||
const IP_IPv6 = 0x29;
|
||||
# Resource Reservation Protocol (RFC2205)
|
||||
const IP_RSVP = 0x2E;
|
||||
# Generic Routing Encapsulation (RFC2784;RFC2890)
|
||||
const IP_GRE = 0x2F;
|
||||
# Open Shortest Path First (RFC1583)
|
||||
const IP_OSPF = 0x59;
|
||||
# Multicast Transport Protocol
|
||||
const IP_MTP = 0x5C;
|
||||
# IP-within-IP Encapsulation Protocol (RFC2003)
|
||||
### error 0x5E;
|
||||
# Ethernet-within-IP Encapsulation Protocol (RFC3378)
|
||||
const IP_ETHERIP = 0x61;
|
||||
# Layer Two Tunneling Protocol Version 3 (RFC3931)
|
||||
const IP_L2TP = 0x73;
|
||||
# Intermediate System to Intermediate System (IS-IS) Protocol over IPv4 (RFC1142;RFC1195)
|
||||
const IP_ISIS = 0x7C;
|
||||
# Fibre Channel
|
||||
const IP_FC = 0x85;
|
||||
# Multiprotocol Label Switching Encapsulated in IP (RFC4023)
|
||||
const IP_MPLS = 0x89;
|
||||
#};
|
||||
|
||||
## Return value for a cookie from a flow
|
||||
## which is not added, modified or deleted
|
||||
## from the bro openflow framework
|
||||
const INVALID_COOKIE = 0xffffffffffffffff;
|
||||
# Openflow pysical port definitions
|
||||
## Send the packet out the input port. This
|
||||
## virual port must be explicitly used in
|
||||
## order to send back out of the input port.
|
||||
const OFPP_IN_PORT = 0xfffffff8;
|
||||
## Perform actions in flow table.
|
||||
## NB: This can only be the destination port
|
||||
## for packet-out messages.
|
||||
const OFPP_TABLE = 0xfffffff9;
|
||||
## Process with normal L2/L3 switching.
|
||||
const OFPP_NORMAL = 0xfffffffa;
|
||||
## All pysical ports except input port and
|
||||
## those disabled by STP.
|
||||
const OFPP_FLOOD = 0xfffffffb;
|
||||
## All pysical ports except input port.
|
||||
const OFPP_ALL = 0xfffffffc;
|
||||
## Send to controller.
|
||||
const OFPP_CONTROLLER = 0xfffffffd;
|
||||
## Local openflow "port".
|
||||
const OFPP_LOCAL = 0xfffffffe;
|
||||
## Wildcard port used only for flow mod (delete) and flow stats requests.
|
||||
const OFPP_ANY = 0xffffffff;
|
||||
# Openflow no buffer constant.
|
||||
const OFP_NO_BUFFER = 0xffffffff;
|
||||
## Send flow removed message when flow
|
||||
## expires or is deleted.
|
||||
const OFPFF_SEND_FLOW_REM = 0x1;
|
||||
## Check for overlapping entries first.
|
||||
const OFPFF_CHECK_OVERLAP = 0x2;
|
||||
## Remark this is for emergency.
|
||||
## Flows added with this are only used
|
||||
## when the controller is disconnected.
|
||||
const OFPFF_EMERG = 0x4;
|
||||
|
||||
# Wildcard table used for table config,
|
||||
# flow stats and flow deletes.
|
||||
const OFPTT_ALL = 0xff;
|
||||
|
||||
## Openflow action_type definitions
|
||||
##
|
||||
## The openflow action type defines
|
||||
## what actions openflow can take
|
||||
## to modify a packet
|
||||
type ofp_action_type: enum {
|
||||
## Output to switch port.
|
||||
OFPAT_OUTPUT = 0x0000,
|
||||
## Set the 802.1q VLAN id.
|
||||
OFPAT_SET_VLAN_VID = 0x0001,
|
||||
## Set the 802.1q priority.
|
||||
OFPAT_SET_VLAN_PCP = 0x0002,
|
||||
## Strip the 802.1q header.
|
||||
OFPAT_STRIP_VLAN = 0x0003,
|
||||
## Ethernet source address.
|
||||
OFPAT_SET_DL_SRC = 0x0004,
|
||||
## Ethernet destination address.
|
||||
OFPAT_SET_DL_DST = 0x0005,
|
||||
## IP source address
|
||||
OFPAT_SET_NW_SRC = 0x0006,
|
||||
## IP destination address.
|
||||
OFPAT_SET_NW_DST = 0x0007,
|
||||
## IP ToS (DSCP field, 6 bits).
|
||||
OFPAT_SET_NW_TOS = 0x0008,
|
||||
## TCP/UDP source port.
|
||||
OFPAT_SET_TP_SRC = 0x0009,
|
||||
## TCP/UDP destination port.
|
||||
OFPAT_SET_TP_DST = 0x000a,
|
||||
## Output to queue.
|
||||
OFPAT_ENQUEUE = 0x000b,
|
||||
## Vendor specific
|
||||
OFPAT_VENDOR = 0xffff,
|
||||
};
|
||||
|
||||
## Openflow flow_mod_command definitions
|
||||
##
|
||||
## The openflow flow_mod_command describes
|
||||
## of what kind an action is.
|
||||
type ofp_flow_mod_command: enum {
|
||||
## New flow.
|
||||
OFPFC_ADD = 0x0,
|
||||
## Modify all matching flows.
|
||||
OFPFC_MODIFY = 0x1,
|
||||
## Modify entry strictly matching wildcards.
|
||||
OFPFC_MODIFY_STRICT = 0x2,
|
||||
## Delete all matching flows.
|
||||
OFPFC_DELETE = 0x3,
|
||||
## Strictly matching wildcards and priority.
|
||||
OFPFC_DELETE_STRICT = 0x4,
|
||||
};
|
||||
|
||||
## Openflow config flag definitions
|
||||
##
|
||||
## TODO: describe
|
||||
type ofp_config_flags: enum {
|
||||
## No special handling for fragments.
|
||||
OFPC_FRAG_NORMAL = 0,
|
||||
## Drop fragments.
|
||||
OFPC_FRAG_DROP = 1,
|
||||
## Reassemble (only if OFPC_IP_REASM set).
|
||||
OFPC_FRAG_REASM = 2,
|
||||
OFPC_FRAG_MASK = 3,
|
||||
};
|
||||
|
||||
}
|
289
scripts/base/frameworks/openflow/main.bro
Normal file
289
scripts/base/frameworks/openflow/main.bro
Normal file
|
@ -0,0 +1,289 @@
|
|||
##! Bro's OpenFlow control framework
|
||||
##!
|
||||
##! This plugin-based framework allows to control OpenFlow capable
|
||||
##! switches by implementing communication to an OpenFlow controller
|
||||
##! via plugins. The framework has to be instantiated via the new function
|
||||
##! in one of the plugins. This framework only offers very low-level
|
||||
##! functionality; if you want to use OpenFlow capable switches, e.g.,
|
||||
##! for shunting, please look at the PACF framework, which provides higher
|
||||
##! level functions and can use the OpenFlow framework as a backend.
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
@load ./consts
|
||||
@load ./types
|
||||
|
||||
export {
|
||||
## Global flow_mod function.
|
||||
##
|
||||
## controller: The controller which should execute the flow modification
|
||||
##
|
||||
## match: The ofp_match record which describes the flow to match.
|
||||
##
|
||||
## flow_mod: The openflow flow_mod record which describes the action to take.
|
||||
##
|
||||
## Returns: F on error or if the plugin does not support the operation, T when the operation was queued.
|
||||
global flow_mod: function(controller: Controller, match: ofp_match, flow_mod: ofp_flow_mod): bool;
|
||||
|
||||
## Clear the current flow table of the controller.
|
||||
##
|
||||
## controller: The controller which should execute the flow modification
|
||||
##
|
||||
## Returns: F on error or if the plugin does not support the operation, T when the operation was queued.
|
||||
global flow_clear: function(controller: Controller): bool;
|
||||
|
||||
## 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(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(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.
|
||||
##
|
||||
## 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(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.
|
||||
##
|
||||
## id: the conn_id record that describes the record.
|
||||
##
|
||||
## reverse: reverse the sources and destinations when creating the match record (default F)
|
||||
##
|
||||
## Returns: ofp_match object for the conn_id record.
|
||||
global match_conn: function(id: conn_id, reverse: bool &default=F): ofp_match;
|
||||
|
||||
# ###
|
||||
# ### Low-level functions for cookie handling and plugin registration.
|
||||
# ###
|
||||
|
||||
## Function to get the unique id out of a given cookie.
|
||||
##
|
||||
## cookie: The openflow match cookie.
|
||||
##
|
||||
## Returns: The cookie unique id.
|
||||
global get_cookie_uid: function(cookie: count): count;
|
||||
|
||||
## Function to get the group id out of a given cookie.
|
||||
##
|
||||
## cookie: The openflow match cookie.
|
||||
##
|
||||
## Returns: The cookie group id.
|
||||
global get_cookie_gid: function(cookie: count): count;
|
||||
|
||||
## Function to generate a new cookie using our group id.
|
||||
##
|
||||
## cookie: The openflow match cookie.
|
||||
##
|
||||
## Returns: The cookie group id.
|
||||
global generate_cookie: function(cookie: count &default=0): count;
|
||||
|
||||
## Function to register a controller instance. This function
|
||||
## is called automatically by the plugin _new functions.
|
||||
##
|
||||
## tpe: type of this plugin
|
||||
##
|
||||
## name: unique name of this controller instance.
|
||||
##
|
||||
## 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 signal that a controller finished activation and is
|
||||
## ready to use. Will throw the ``OpenFlow::controller_activated``
|
||||
## event.
|
||||
global controller_init_done: function(controller: Controller);
|
||||
|
||||
## Event that is raised once a controller finishes initialization
|
||||
## and is completely activated.
|
||||
## name: unique name of this controller instance.
|
||||
##
|
||||
## controller: The controller that finished activation.
|
||||
global OpenFlow::controller_activated: event(name: string, 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;
|
||||
local proto = IP_TCP;
|
||||
|
||||
local orig_h: addr;
|
||||
local orig_p: port;
|
||||
local resp_h: addr;
|
||||
local resp_p: port;
|
||||
|
||||
if ( reverse == F )
|
||||
{
|
||||
orig_h = id$orig_h;
|
||||
orig_p = id$orig_p;
|
||||
resp_h = id$resp_h;
|
||||
resp_p = id$resp_p;
|
||||
}
|
||||
else
|
||||
{
|
||||
orig_h = id$resp_h;
|
||||
orig_p = id$resp_p;
|
||||
resp_h = id$orig_h;
|
||||
resp_p = id$orig_p;
|
||||
}
|
||||
|
||||
if ( is_v6_addr(orig_h) )
|
||||
dl_type = ETH_IPv6;
|
||||
|
||||
if ( is_udp_port(orig_p) )
|
||||
proto = IP_UDP;
|
||||
else if ( is_icmp_port(orig_p) )
|
||||
proto = IP_ICMP;
|
||||
|
||||
return ofp_match(
|
||||
$dl_type=dl_type,
|
||||
$nw_proto=proto,
|
||||
$nw_src=addr_to_subnet(orig_h),
|
||||
$tp_src=port_to_count(orig_p),
|
||||
$nw_dst=addr_to_subnet(resp_h),
|
||||
$tp_dst=port_to_count(resp_p)
|
||||
);
|
||||
}
|
||||
|
||||
# local function to forge a flow_mod cookie for this framework.
|
||||
# all flow entries from the openflow framework should have the
|
||||
# 42 bit of the cookie set.
|
||||
function generate_cookie(cookie: count &default=0): count
|
||||
{
|
||||
local c = BRO_COOKIE_ID * COOKIE_BID_START;
|
||||
|
||||
if ( cookie >= COOKIE_UID_SIZE )
|
||||
Reporter::warning(fmt("The given cookie uid '%d' is > 32bit and will be discarded", cookie));
|
||||
else
|
||||
c += cookie;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
# local function to check if a given flow_mod cookie is forged from this framework.
|
||||
function is_valid_cookie(cookie: count): bool
|
||||
{
|
||||
if ( cookie / COOKIE_BID_START == BRO_COOKIE_ID )
|
||||
return T;
|
||||
|
||||
Reporter::warning(fmt("The given Openflow cookie '%d' is not valid", cookie));
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
function get_cookie_uid(cookie: count): count
|
||||
{
|
||||
if( is_valid_cookie(cookie) )
|
||||
return (cookie - ((cookie / COOKIE_GID_START) * COOKIE_GID_START));
|
||||
|
||||
return INVALID_COOKIE;
|
||||
}
|
||||
|
||||
function get_cookie_gid(cookie: count): count
|
||||
{
|
||||
if( is_valid_cookie(cookie) )
|
||||
return (
|
||||
(cookie - (COOKIE_BID_START * BRO_COOKIE_ID) -
|
||||
(cookie - ((cookie / COOKIE_GID_START) * COOKIE_GID_START))) /
|
||||
COOKIE_GID_START
|
||||
);
|
||||
|
||||
return INVALID_COOKIE;
|
||||
}
|
||||
|
||||
function controller_init_done(controller: Controller)
|
||||
{
|
||||
if ( controller$state$_name !in name_to_controller )
|
||||
{
|
||||
Reporter::error(fmt("Openflow initialized unknown plugin %s successfully?", controller$state$_name));
|
||||
return;
|
||||
}
|
||||
|
||||
controller$state$_activated = T;
|
||||
event OpenFlow::controller_activated(controller$state$_name, controller);
|
||||
}
|
||||
|
||||
# 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(fmt("OpenFlow Controller %s was already registered. Ignored duplicate registration", controller$state$_name));
|
||||
return;
|
||||
}
|
||||
|
||||
name_to_controller[controller$state$_name] = controller;
|
||||
|
||||
if ( controller?$init )
|
||||
controller$init(controller$state);
|
||||
else
|
||||
controller_init_done(controller);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
44
scripts/base/frameworks/openflow/non-cluster.bro
Normal file
44
scripts/base/frameworks/openflow/non-cluster.bro
Normal file
|
@ -0,0 +1,44 @@
|
|||
@load ./main
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
# the flow_mod function wrapper
|
||||
function flow_mod(controller: Controller, match: ofp_match, flow_mod: ofp_flow_mod): bool
|
||||
{
|
||||
if ( ! controller$state$_activated )
|
||||
return F;
|
||||
|
||||
if ( controller?$flow_mod )
|
||||
return controller$flow_mod(controller$state, match, flow_mod);
|
||||
else
|
||||
return F;
|
||||
}
|
||||
|
||||
function flow_clear(controller: Controller): bool
|
||||
{
|
||||
if ( ! controller$state$_activated )
|
||||
return F;
|
||||
|
||||
if ( controller?$flow_clear )
|
||||
return controller$flow_clear(controller$state);
|
||||
else
|
||||
return F;
|
||||
}
|
||||
|
||||
function register_controller(tpe: OpenFlow::Plugin, name: string, controller: Controller)
|
||||
{
|
||||
controller$state$_name = cat(tpe, name);
|
||||
controller$state$_plugin = tpe;
|
||||
|
||||
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);
|
||||
}
|
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;
|
||||
}
|
132
scripts/base/frameworks/openflow/types.bro
Normal file
132
scripts/base/frameworks/openflow/types.bro
Normal file
|
@ -0,0 +1,132 @@
|
|||
##! Types used by the OpenFlow framework.
|
||||
|
||||
module OpenFlow;
|
||||
|
||||
@load ./consts
|
||||
|
||||
export {
|
||||
## Available openflow plugins
|
||||
type Plugin: enum {
|
||||
## Internal placeholder plugin
|
||||
INVALID,
|
||||
};
|
||||
|
||||
## Controller related state.
|
||||
## Can be redefined by plugins to
|
||||
## add state.
|
||||
type ControllerState: record {
|
||||
## Internally set to the type of plugin used.
|
||||
_plugin: Plugin &optional;
|
||||
## Internally set to the unique name of the controller.
|
||||
_name: string &optional;
|
||||
## Internally set to true once the controller is activated
|
||||
_activated: bool &default=F;
|
||||
} &redef;
|
||||
|
||||
## Openflow match definition.
|
||||
##
|
||||
## The openflow match record describes
|
||||
## which packets match to a specific
|
||||
## rule in a flow table.
|
||||
type ofp_match: record {
|
||||
# Input switch port.
|
||||
in_port: count &optional;
|
||||
# Ethernet source address.
|
||||
dl_src: string &optional;
|
||||
# Ethernet destination address.
|
||||
dl_dst: string &optional;
|
||||
# Input VLAN id.
|
||||
dl_vlan: count &optional;
|
||||
# Input VLAN priority.
|
||||
dl_vlan_pcp: count &optional;
|
||||
# Ethernet frame type.
|
||||
dl_type: count &optional;
|
||||
# IP ToS (actually DSCP field, 6bits).
|
||||
nw_tos: count &optional;
|
||||
# IP protocol or lower 8 bits of ARP opcode.
|
||||
nw_proto: count &optional;
|
||||
# At the moment, we store both v4 and v6 in the same fields.
|
||||
# This is not how OpenFlow does it, we might want to change that...
|
||||
# IP source address.
|
||||
nw_src: subnet &optional;
|
||||
# IP destination address.
|
||||
nw_dst: subnet &optional;
|
||||
# TCP/UDP source port.
|
||||
tp_src: count &optional;
|
||||
# TCP/UDP destination port.
|
||||
tp_dst: count &optional;
|
||||
} &log;
|
||||
|
||||
## The actions that can be taken in a flow.
|
||||
## (Sepearate record to make ofp_flow_mod less crowded)
|
||||
type ofp_flow_action: record {
|
||||
## Output ports to send data to.
|
||||
out_ports: vector of count &default=vector();
|
||||
## set vlan vid to this value
|
||||
vlan_vid: count &optional;
|
||||
## set vlan priority to this value
|
||||
vlan_pcp: count &optional;
|
||||
## strip vlan tag
|
||||
vlan_strip: bool &default=F;
|
||||
## set ethernet source address
|
||||
dl_src: string &optional;
|
||||
## set ethernet destination address
|
||||
dl_dst: string &optional;
|
||||
## set ip tos to this value
|
||||
nw_tos: count &optional;
|
||||
## set source to this ip
|
||||
nw_src: addr &optional;
|
||||
## set destination to this ip
|
||||
nw_dst: addr &optional;
|
||||
## set tcp/udp source port
|
||||
tp_src: count &optional;
|
||||
## set tcp/udp destination port
|
||||
tp_dst: count &optional;
|
||||
} &log;
|
||||
|
||||
## Openflow flow_mod definition, describing the action to perform.
|
||||
type ofp_flow_mod: record {
|
||||
## Opaque controller-issued identifier.
|
||||
# This is optional in the specification - but let's force
|
||||
# it so we always can identify our flows...
|
||||
cookie: count; # &default=BRO_COOKIE_ID * COOKIE_BID_START;
|
||||
# Flow actions
|
||||
## Table to put the flow in. OFPTT_ALL can be used for delete,
|
||||
## to delete flows from all matching tables.
|
||||
table_id: count &optional;
|
||||
## One of OFPFC_*.
|
||||
command: ofp_flow_mod_command; # &default=OFPFC_ADD;
|
||||
## Idle time before discarding (seconds).
|
||||
idle_timeout: count &default=0;
|
||||
## Max time before discarding (seconds).
|
||||
hard_timeout: count &default=0;
|
||||
## Priority level of flow entry.
|
||||
priority: count &default=0;
|
||||
## For OFPFC_DELETE* commands, require matching entried to include
|
||||
## this as an output port/group. OFPP_ANY/OFPG_ANY means no restrictions.
|
||||
out_port: count &optional;
|
||||
out_group: count &optional;
|
||||
## Bitmap of the OFPFF_* flags
|
||||
flags: count &default=0;
|
||||
## Actions to take on match
|
||||
actions: ofp_flow_action &default=ofp_flow_action();
|
||||
} &log;
|
||||
|
||||
## Controller record representing an openflow controller
|
||||
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;
|
||||
## one-time initialization function. If defined, controller_init_done has to be called once initialization finishes.
|
||||
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
|
||||
flow_clear: function(state: ControllerState): bool &optional;
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue