mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
[ADD] made code event based, changed code style
the openflow framework does now use events to signal the success or failure of openflow commands, further the reporter framework is used to log errors. added bro unique cookie, so the framework can recognize which flows it installed and which not. documented all of the code. the code style should now me more like the rest of the bro code.
This commit is contained in:
parent
bf6dc12be4
commit
c705375537
3 changed files with 381 additions and 179 deletions
|
@ -1,87 +1,126 @@
|
|||
@load ./utils/const.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 {
|
||||
# ofp_port: enum {
|
||||
# Maximum number of physical switch ports.
|
||||
## 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
|
||||
## Maximum number of physical switch ports.
|
||||
const OFPP_MAX = 0xff00;
|
||||
########################
|
||||
# Fake output "ports". #
|
||||
########################
|
||||
# Send the packet out the input port. This
|
||||
# virual port must be explicitly used in
|
||||
# order to send back out of the input port.
|
||||
## 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 = 0xfff8;
|
||||
# Perform actions in flow table.
|
||||
# NB: This can only be the destination port
|
||||
# for packet-out messages.
|
||||
## Perform actions in flow table.
|
||||
## NB: This can only be the destination port
|
||||
## for packet-out messages.
|
||||
const OFPP_TABLE = 0xfff9;
|
||||
# Process with normal L2/L3 switching.
|
||||
## Process with normal L2/L3 switching.
|
||||
const OFPP_NORMAL = 0xfffa;
|
||||
# All pysical ports except input port and
|
||||
# those disabled by STP.
|
||||
## All pysical ports except input port and
|
||||
## those disabled by STP.
|
||||
const OFPP_FLOOD = 0xfffb;
|
||||
# All pysical ports except input port.
|
||||
## All pysical ports except input port.
|
||||
const OFPP_ALL = 0xfffc;
|
||||
# Send to controller.
|
||||
## Send to controller.
|
||||
const OFPP_CONTROLLER = 0xfffd;
|
||||
# Local openflow "port".
|
||||
## Local openflow "port".
|
||||
const OFPP_LOCAL = 0xfffe;
|
||||
# Not associated with a pysical port.
|
||||
## Not associated with a pysical port.
|
||||
const OFPP_NONE = 0xffff;
|
||||
# }
|
||||
|
||||
## 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.
|
||||
## Output to switch port.
|
||||
OFPAT_OUTPUT = 0x0000,
|
||||
# Set the 802.1q VLAN id.
|
||||
## Set the 802.1q VLAN id.
|
||||
OFPAT_SET_VLAN_VID = 0x0001,
|
||||
# Set the 802.1q priority.
|
||||
## Set the 802.1q priority.
|
||||
OFPAT_SET_VLAN_PCP = 0x0002,
|
||||
# Strip the 802.1q header.
|
||||
## Strip the 802.1q header.
|
||||
OFPAT_STRIP_VLAN = 0x0003,
|
||||
# Ethernet source address.
|
||||
## Ethernet source address.
|
||||
OFPAT_SET_DL_SRC = 0x0004,
|
||||
# Ethernet destination address.
|
||||
## Ethernet destination address.
|
||||
OFPAT_SET_DL_DST = 0x0005,
|
||||
# IP source address
|
||||
## IP source address
|
||||
OFPAT_SET_NW_SRC = 0x0006,
|
||||
# IP destination address.
|
||||
## IP destination address.
|
||||
OFPAT_SET_NW_DST = 0x0007,
|
||||
# IP ToS (DSCP field, 6 bits).
|
||||
## IP ToS (DSCP field, 6 bits).
|
||||
OFPAT_SET_NW_TOS = 0x0008,
|
||||
# TCP/UDP source port.
|
||||
## TCP/UDP source port.
|
||||
OFPAT_SET_TP_SRC = 0x0009,
|
||||
# TCP/UDP destination port.
|
||||
## TCP/UDP destination port.
|
||||
OFPAT_SET_TP_DST = 0x000a,
|
||||
# Output to queue.
|
||||
## 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,
|
||||
# Modify all matching flows.
|
||||
OFPFC_MODIFY,
|
||||
# Modify entry strictly matching wildcards.
|
||||
OFPFC_MODIFY_STRICT,
|
||||
# Delete all matching flows.
|
||||
OFPFC_DELETE,
|
||||
# Strictly matching wildcards and priority.
|
||||
OFPFC_DELETE_STRICT,
|
||||
## 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.
|
||||
## No special handling for fragments.
|
||||
OFPC_FRAG_NORMAL = 0,
|
||||
# Drop fragments.
|
||||
## Drop fragments.
|
||||
OFPC_FRAG_DROP = 1,
|
||||
# Reassemble (only if OFPC_IP_REASM set).
|
||||
## Reassemble (only if OFPC_IP_REASM set).
|
||||
OFPC_FRAG_REASM = 2,
|
||||
OFPC_FRAG_MASK = 3,
|
||||
};
|
||||
|
||||
|
||||
## Openflow match definition.
|
||||
##
|
||||
## The openflow match record describes
|
||||
## which packets match to a specific
|
||||
## rule in a flow table.
|
||||
type ofp_match: record {
|
||||
# Wildcard fields.
|
||||
#wildcards: count &optional;
|
||||
|
@ -111,80 +150,199 @@ export {
|
|||
tp_dst: port &optional;
|
||||
};
|
||||
|
||||
## Openflow actions definition.
|
||||
##
|
||||
## A action describes what should
|
||||
## happen with packets of the matching
|
||||
## flow.
|
||||
type ofp_action_output: record {
|
||||
# this should never change, but there are not
|
||||
# constants available in records
|
||||
# defaults to OFPAT_OUTPUT
|
||||
## this should never change, but there are not
|
||||
## constants available in records
|
||||
## defaults to OFPAT_OUTPUT
|
||||
_type: ofp_action_type &default=OFPAT_OUTPUT;
|
||||
#_len: count &default=8;
|
||||
# Output port.
|
||||
## Output port.
|
||||
_port: count &default=OFPP_FLOOD;
|
||||
#_max_len: count &optional;
|
||||
};
|
||||
|
||||
#type ofp_flow_mod_flags: enum {
|
||||
# Send flow removed message when flow
|
||||
# expires or is deleted.
|
||||
# Openflow flow_mod_flags definition
|
||||
## Send flow removed message when flow
|
||||
## expires or is deleted.
|
||||
const OFPFF_SEND_FLOW_REM = 0x1;
|
||||
# Check for overlapping entries first.
|
||||
## 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.
|
||||
## Remark this is for emergency.
|
||||
## Flows added with this are only used
|
||||
## when the controller is disconnected.
|
||||
const OFPFF_EMERG = 0x4;
|
||||
#};
|
||||
|
||||
## Openflow flow_mod definition.
|
||||
## It describes the flow to match and
|
||||
## how it should be modified.
|
||||
type ofp_flow_mod: record {
|
||||
# header: ofp_header;
|
||||
# Fields to match
|
||||
## Fields to match
|
||||
match: ofp_match;
|
||||
# Opaque controller-issued identifier.
|
||||
cookie: count &optional;
|
||||
|
||||
## Opaque controller-issued identifier.
|
||||
cookie: count &default=BRO_COOKIE_ID * COOKIE_BID_START;
|
||||
# Flow actions
|
||||
|
||||
# One of OFPFC_*.
|
||||
## One of OFPFC_*.
|
||||
command: ofp_flow_mod_command &default=OFPFC_ADD;
|
||||
# Idle time befor discarding (seconds).
|
||||
## Idle time befor discarding (seconds).
|
||||
idle_timeout: count &optional;
|
||||
# Max time before discarding (seconds).
|
||||
## Max time before discarding (seconds).
|
||||
hard_timeout: count &optional;
|
||||
# Priority level of flow entry.
|
||||
## Priority level of flow entry.
|
||||
priority: count &optional;
|
||||
# Buffered packet to apply to (or -1).
|
||||
# Not meaningful for OFPFC_DELETE*.
|
||||
## Buffered packet to apply to (or -1).
|
||||
## Not meaningful for OFPFC_DELETE*.
|
||||
buffer_id: count &optional;
|
||||
# For OFPFC_DELETE* commands, require
|
||||
# matching entries to include this as an
|
||||
# output port. A value of OFPP_NONE
|
||||
# indicates no restrictions
|
||||
## For OFPFC_DELETE* commands, require
|
||||
## matching entries to include this as an
|
||||
## output port. A value of OFPP_NONE
|
||||
## indicates no restrictions.
|
||||
out_port: count &optional;
|
||||
# One of OFPFF_*.
|
||||
## One of OFPFF_*.
|
||||
flags: count &optional;
|
||||
## A list of actions to perform.
|
||||
actions: vector of ofp_action_output;
|
||||
};
|
||||
|
||||
## Body of reply to OFPST_FLOW request.
|
||||
type ofp_flow_stats: record {
|
||||
## Length of this entry
|
||||
length: count;
|
||||
## 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;
|
||||
};
|
||||
|
||||
## Function to modify flows in a openflow flow table.
|
||||
##
|
||||
## dpid: The openflow controller datapath id.
|
||||
##
|
||||
## flow_mod: The openflow flow_mod record which describes
|
||||
## the flow to delete, modify or add.
|
||||
##
|
||||
## Returns: T, if successful, else F.
|
||||
global flow_mod: function(dpid: count, flow_mod: ofp_flow_mod): bool;
|
||||
|
||||
## 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;
|
||||
|
||||
## Event to signal that a flow has been successfully modified.
|
||||
##
|
||||
## flow_mod: The openflow flow_mod record which describes
|
||||
## the flow to delete, modify or add.
|
||||
##
|
||||
## msg: Message to describe the event.
|
||||
global Openflow::flow_mod_success: event(flow_mod: ofp_flow_mod, msg: string &default = "Flow successfully modified");
|
||||
|
||||
## Event to signal that a flow mod has failed.
|
||||
##
|
||||
## flow_mod: The openflow flow_mod record which describes
|
||||
## the flow to delete, modify ord add.
|
||||
##
|
||||
## msg: Message to describe the event.
|
||||
global Openflow::flow_mod_failure: event(flow_mod: ofp_flow_mod, msg: string &default = "Could not modify flow");
|
||||
}
|
||||
|
||||
|
||||
# Flow Modification function prototype
|
||||
type FlowModFunc: function(dpid: count, flow_mod: ofp_flow_mod): bool;
|
||||
|
||||
# Flow Modification function
|
||||
global FlowMod: FlowModFunc;
|
||||
|
||||
# Hook for registering openflow plugins
|
||||
global register_openflow_plugin: hook();
|
||||
|
||||
function register_openflow_mod_func(func: FlowModFunc) {
|
||||
FlowMod = func;
|
||||
}
|
||||
|
||||
function flow_mod(dpid: count, flow_mod: ofp_flow_mod): bool {
|
||||
return FlowMod(dpid, flow_mod);
|
||||
}
|
||||
# Function for plugins to call when they
|
||||
# register their flow_mod function.
|
||||
function register_openflow_mod_func(func: FlowModFunc)
|
||||
{
|
||||
flow_mod = func;
|
||||
}
|
||||
|
||||
event bro_init() &priority=100000 {
|
||||
|
||||
# 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 a 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;
|
||||
}
|
||||
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
# Call all of the plugin registration hooks
|
||||
hook register_openflow_plugin();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,17 +3,51 @@
|
|||
@load base/utils/exec
|
||||
@load base/utils/active-http
|
||||
|
||||
|
||||
module Openflow;
|
||||
|
||||
|
||||
export {
|
||||
const controller_ip = "10.255.0.20" &redef;
|
||||
## The Ryu openflow controller IP.
|
||||
const controller_ip = "0.0.0.0" &redef;
|
||||
## The port where the ReST API listens on.
|
||||
const controller_port = "8080" &redef;
|
||||
|
||||
## Ryu error definitions.
|
||||
type RyuError: enum {
|
||||
## The controller IP needs to be redefined.
|
||||
CONTROLLER_IP_REDEF,
|
||||
## The openflow command type is not available
|
||||
## for this ryu openflow plugin.
|
||||
COMMAND_TYPE_NOT_AVAILABLE,
|
||||
## The openflow action type is not available
|
||||
## for this ryu openflow plugin.
|
||||
ACTION_TYPE_NOT_AVAILABLE,
|
||||
};
|
||||
|
||||
## Ryu error event.
|
||||
##
|
||||
## flow_mod: The openflow flow_mod record which describes
|
||||
## the flow to delete, modify or add.
|
||||
##
|
||||
## error: The error why the plugin aborted.
|
||||
##
|
||||
## msg: More detailed error description.
|
||||
global Openflow::ryu_error: event(flow_mod: ofp_flow_mod, error: RyuError, msg: string &default="");
|
||||
}
|
||||
|
||||
|
||||
# Openflow no buffer constant.
|
||||
const OFP_NO_BUFFER = 0xffffffff;
|
||||
|
||||
|
||||
# Ryu ReST API flow_mod URL-path
|
||||
const RYU_FLOWENTRY_PATH = "/stats/flowentry/";
|
||||
|
||||
|
||||
# Ryu ReST API action_output type.
|
||||
type ryu_flow_action_output: record {
|
||||
# Ryu uses strings as its ReST API output action.
|
||||
# The type should be never changed...
|
||||
# but constants are not possible in a record.
|
||||
_type: string &default="OUTPUT";
|
||||
|
@ -21,9 +55,11 @@ type ryu_flow_action_output: record {
|
|||
_port: count;
|
||||
};
|
||||
|
||||
# The restAPI documentation can be found at
|
||||
|
||||
# The ReST API documentation can be found at
|
||||
# https://media.readthedocs.org/pdf/ryu/latest/ryu.pdf
|
||||
# on page 278-299
|
||||
# on page 278-299 (30.10.2014)
|
||||
# Ryu ReST API flow_mod type.
|
||||
type ryu_flow_mod: record {
|
||||
dpid: count;
|
||||
cookie: count &optional;
|
||||
|
@ -38,26 +74,40 @@ type ryu_flow_mod: record {
|
|||
actions: vector of ryu_flow_action_output;
|
||||
};
|
||||
|
||||
# register the ryu openflow plugin flow_mod function
|
||||
hook register_openflow_plugin() {
|
||||
|
||||
# Hook to register the Ryu openflow plugin's flow_mod function
|
||||
# as the one the openflow framework should use.
|
||||
hook register_openflow_plugin()
|
||||
{
|
||||
register_openflow_mod_func(
|
||||
function(dpid: count, flow_mod: ofp_flow_mod): bool {
|
||||
function(dpid: count, flow_mod: ofp_flow_mod): bool
|
||||
{
|
||||
# Check if the controller_ip has been redefined.
|
||||
if(controller_ip == "0.0.0.0")
|
||||
{
|
||||
Reporter::warning(fmt("The constant Openflow::controller_ip must be redefined"));
|
||||
event Openflow::ryu_error(flow_mod, CONTROLLER_IP_REDEF, cat(controller_ip));
|
||||
return F;
|
||||
}
|
||||
# Generate ryu_flow_actions because their type differs (using strings as type).
|
||||
local _flow_actions: vector of ryu_flow_action_output;
|
||||
for(i in flow_mod$actions) {
|
||||
switch(flow_mod$actions[i]$_type) {
|
||||
for(i in flow_mod$actions)
|
||||
{
|
||||
switch(flow_mod$actions[i]$_type)
|
||||
{
|
||||
case OFPAT_OUTPUT:
|
||||
_flow_actions[|_flow_actions|] = ryu_flow_action_output($_port=flow_mod$actions[i]$_port);
|
||||
break;
|
||||
default:
|
||||
print fmt("Error: flow action '%s' not available", flow_mod$actions[i]$_type);
|
||||
Reporter::warning(fmt("The given Openflow action type '%s' is not available", flow_mod$actions[i]$_type));
|
||||
event Openflow::ryu_error(flow_mod, ACTION_TYPE_NOT_AVAILABLE, cat(flow_mod$actions[i]$_type));
|
||||
return F;
|
||||
}
|
||||
}
|
||||
}
|
||||
# Generate our ryu_flow_mod record for the restAPI call.
|
||||
# Generate our ryu_flow_mod record for the ReST API call.
|
||||
local _flow_mod: ryu_flow_mod = ryu_flow_mod(
|
||||
$dpid=dpid,
|
||||
$cookie=flow_mod$cookie,
|
||||
$cookie=generate_cookie(flow_mod$cookie),
|
||||
$idle_timeout=flow_mod$idle_timeout,
|
||||
$hard_timeout=flow_mod$hard_timeout,
|
||||
$match=flow_mod$match,
|
||||
|
@ -65,7 +115,8 @@ hook register_openflow_plugin() {
|
|||
);
|
||||
# Type of the command
|
||||
local command_type: string;
|
||||
switch(flow_mod$command) {
|
||||
switch(flow_mod$command)
|
||||
{
|
||||
case OFPFC_ADD:
|
||||
command_type = "add";
|
||||
break;
|
||||
|
@ -73,76 +124,30 @@ hook register_openflow_plugin() {
|
|||
command_type = "delete";
|
||||
break;
|
||||
default:
|
||||
print fmt("Error: command type '%s' not available", flow_mod$command);
|
||||
Reporter::warning(fmt("The given Openflow command type '%s' is not available", result$body));
|
||||
event Openflow::ryu_error(flow_mod, COMMAND_TYPE_NOT_AVAILABLE, cat(flow_mod$command));
|
||||
return F;
|
||||
}
|
||||
# Create the ActiveHTTP request and convert the record to a ryu restAPI JSON string
|
||||
}
|
||||
# Create the ActiveHTTP request and convert the record to a Ryu ReST API JSON string
|
||||
local request: ActiveHTTP::Request = ActiveHTTP::Request(
|
||||
$url=cat("http://", controller_ip, ":", controller_port, RYU_FLOWENTRY_PATH, command_type),
|
||||
$method="POST",
|
||||
$client_data=JSON::convert(_flow_mod)
|
||||
);
|
||||
# Execute call to ryu's restAPI
|
||||
when(local result = ActiveHTTP::request(request)) {
|
||||
if(result$code == 200) {
|
||||
print fmt(
|
||||
"%sed flow %s:%s -> %s:%s",
|
||||
command_type,
|
||||
flow_mod$match$nw_src,
|
||||
flow_mod$match$tp_src,
|
||||
flow_mod$match$nw_dst,
|
||||
flow_mod$match$tp_dst
|
||||
);
|
||||
} else {
|
||||
print fmt("Error: could not %s flow, restAPI returned:\n%s", command_type, result);
|
||||
# Execute call to Ryu's ReST API
|
||||
when(local result = ActiveHTTP::request(request))
|
||||
{
|
||||
if(result$code == 200)
|
||||
event Openflow::flow_mod_success(flow_mod, result$body);
|
||||
else
|
||||
{
|
||||
Reporter::warning(fmt("Flow modification failed with error: %s", result$body));
|
||||
event Openflow::flow_mod_failure(flow_mod, result$body);
|
||||
return F;
|
||||
}
|
||||
}
|
||||
|
||||
# Add reverse flow because openflow only uses unidirectional flows.
|
||||
if(|flow_mod$actions| == 1 && (flow_mod$match$dl_type == ETH_IPv4 || flow_mod$match$dl_type == ETH_IPv6)) {
|
||||
local reverse_flow_match: ofp_match;
|
||||
local reverse_flow_actions: vector of ryu_flow_action_output;
|
||||
reverse_flow_actions[|reverse_flow_actions|] = ryu_flow_action_output($_port=flow_mod$match$in_port);
|
||||
reverse_flow_match = ofp_match(
|
||||
$in_port=flow_mod$actions[0]$_port,
|
||||
$dl_type=flow_mod$match$dl_type,
|
||||
$nw_proto=flow_mod$match$nw_proto,
|
||||
$nw_src=flow_mod$match$nw_dst,
|
||||
$nw_dst=flow_mod$match$nw_src,
|
||||
$tp_src=flow_mod$match$tp_dst,
|
||||
$tp_dst=flow_mod$match$tp_src
|
||||
);
|
||||
local reverse_flow_mod: ryu_flow_mod = ryu_flow_mod(
|
||||
$dpid=dpid,
|
||||
$cookie=flow_mod$cookie,
|
||||
$idle_timeout=flow_mod$idle_timeout,
|
||||
$hard_timeout=flow_mod$hard_timeout,
|
||||
$match=reverse_flow_match,
|
||||
$actions=reverse_flow_actions
|
||||
);
|
||||
local reverse_request: ActiveHTTP::Request = ActiveHTTP::Request(
|
||||
$url=cat("http://", controller_ip, ":", controller_port, RYU_FLOWENTRY_PATH, command_type),
|
||||
$method="POST",
|
||||
$client_data=JSON::convert(reverse_flow_mod)
|
||||
);
|
||||
when(local result2 = ActiveHTTP::request(reverse_request)) {
|
||||
if(result2$code == 200) {
|
||||
print fmt(
|
||||
"%sed flow %s:%s -> %s:%s",
|
||||
command_type,
|
||||
reverse_flow_match$nw_src,
|
||||
reverse_flow_match$tp_src,
|
||||
reverse_flow_match$nw_dst,
|
||||
reverse_flow_match$tp_dst
|
||||
);
|
||||
} else {
|
||||
print fmt("Error: could not %s flow, restAPI returned:\n%s", command_type, result2);
|
||||
return F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ module OpenflowShunt;
|
|||
|
||||
|
||||
# default constants which are not automatically gathered.
|
||||
redef Openflow::controller_ip = "10.255.0.20";
|
||||
const dpid = 4222282094087168;
|
||||
const cookie = 0;
|
||||
const idle_timeout = 30;
|
||||
|
@ -34,7 +35,8 @@ export {
|
|||
global shunt_triggered: event(c: connection);
|
||||
}
|
||||
|
||||
function size_callback(c: connection, cnt: count): interval {
|
||||
function size_callback(c: connection, cnt: count): interval
|
||||
{
|
||||
# print flow traffic.
|
||||
print fmt(
|
||||
"%s:%s <-> %s:%s reached %s/%s",
|
||||
|
@ -46,17 +48,20 @@ function size_callback(c: connection, cnt: count): interval {
|
|||
size_threshold
|
||||
);
|
||||
# if traffic exceeds the given threshold, remove flow.
|
||||
if ( c$orig$num_bytes_ip + c$resp$num_bytes_ip >= size_threshold ) {
|
||||
if ( c$orig$num_bytes_ip + c$resp$num_bytes_ip >= size_threshold )
|
||||
{
|
||||
# create openflow flow_mod add records from connection data and given default constants
|
||||
local actions: vector of Openflow::ofp_action_output;
|
||||
local reverse_actions: vector of Openflow::ofp_action_output;
|
||||
actions[|actions|] = Openflow::ofp_action_output($_port=out_port);
|
||||
reverse_actions[|reverse_actions|] = Openflow::ofp_action_output($_port=in_port);
|
||||
# flow layer 4 protocol
|
||||
local nw_proto = Openflow::IP_TCP;
|
||||
if(is_udp_port(c$id$orig_p)) {
|
||||
if(is_udp_port(c$id$orig_p))
|
||||
nw_proto = Openflow::IP_UDP;
|
||||
} else if(is_icmp_port(c$id$orig_p)) {
|
||||
else if(is_icmp_port(c$id$orig_p))
|
||||
nw_proto = Openflow::IP_ICMP;
|
||||
}
|
||||
|
||||
local match: Openflow::ofp_match = [
|
||||
$in_port=in_port,
|
||||
$nw_src=c$id$orig_h,
|
||||
|
@ -65,10 +70,19 @@ function size_callback(c: connection, cnt: count): interval {
|
|||
$tp_src=c$id$orig_p,
|
||||
$tp_dst=c$id$resp_p
|
||||
];
|
||||
|
||||
local reverse_match: Openflow::ofp_match = [
|
||||
$in_port=out_port,
|
||||
$nw_src=c$id$resp_h,
|
||||
$nw_dst=c$id$orig_h,
|
||||
$nw_proto=nw_proto,
|
||||
$tp_src=c$id$resp_p,
|
||||
$tp_dst=c$id$orig_p
|
||||
];
|
||||
|
||||
local command = Openflow::OFPFC_ADD;
|
||||
if(delete_flow) {
|
||||
if(delete_flow)
|
||||
command = Openflow::OFPFC_DELETE;
|
||||
}
|
||||
local flow_mod: Openflow::ofp_flow_mod = [
|
||||
$match=match,
|
||||
$cookie=cookie,
|
||||
|
@ -77,26 +91,51 @@ function size_callback(c: connection, cnt: count): interval {
|
|||
$hard_timeout=hard_timeout,
|
||||
$actions=actions
|
||||
];
|
||||
local reverse_flow_mod: Openflow::ofp_flow_mod = [
|
||||
$match=reverse_match,
|
||||
$cookie=cookie,
|
||||
$command=command,
|
||||
$idle_timeout=idle_timeout,
|
||||
$hard_timeout=hard_timeout,
|
||||
$actions=reverse_actions
|
||||
];
|
||||
|
||||
# call openflow framework
|
||||
when ( local result = Openflow::flow_mod(dpid, flow_mod) ) {
|
||||
if(result) {
|
||||
event OpenflowShunt::shunt_triggered(c);
|
||||
if(Openflow::flow_mod(dpid, flow_mod) && Openflow::flow_mod(dpid, reverse_flow_mod)) {
|
||||
event shunt_triggered(c);
|
||||
}
|
||||
|
||||
if(delete_flow)
|
||||
{
|
||||
delete_flow = F;
|
||||
return -1sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete_flow = T;
|
||||
return 15sec;
|
||||
}
|
||||
}
|
||||
|
||||
if(delete_flow) {
|
||||
return -1sec;
|
||||
} else {
|
||||
delete_flow = T;
|
||||
return 15sec;
|
||||
}
|
||||
return poll_interval;
|
||||
}
|
||||
|
||||
return poll_interval;
|
||||
}
|
||||
|
||||
event connection_established(c: connection) {
|
||||
event connection_established(c: connection)
|
||||
{
|
||||
print fmt("new connection");
|
||||
ConnPolling::watch(c, size_callback, 0, 0secs);
|
||||
}
|
||||
}
|
||||
|
||||
event Openflow::flow_mod_success(flow_mod: Openflow::ofp_flow_mod, msg: string)
|
||||
{
|
||||
print fmt("succsess, %s", cat(flow_mod));
|
||||
}
|
||||
|
||||
event Openflow::flow_mod_failure(flow_mod: Openflow::ofp_flow_mod, msg: string)
|
||||
{
|
||||
print fmt("failed, %s", cat(flow_mod));
|
||||
}
|
||||
event Openflow::ryu_error(flow_mod: Openflow::ofp_flow_mod, error: Openflow::RyuError, msg: string)
|
||||
{
|
||||
print fmt("ERROR: %s, msg: %s\n%s", error, msg, flow_mod);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue