mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 00:28:21 +00:00
148 lines
4.5 KiB
Text
148 lines
4.5 KiB
Text
@load ../main
|
|
@load ../utils/json
|
|
@load base/utils/exec
|
|
@load base/utils/active-http
|
|
|
|
module Openflow;
|
|
|
|
export {
|
|
const controller_ip = "10.255.0.20" &redef;
|
|
const controller_port = "8080" &redef;
|
|
}
|
|
|
|
const OFP_NO_BUFFER = 0xffffffff;
|
|
const RYU_FLOWENTRY_PATH = "/stats/flowentry/";
|
|
|
|
type ryu_flow_action_output: record {
|
|
# The type should be never changed...
|
|
# but constants are not possible in a record.
|
|
_type: string &default="OUTPUT";
|
|
# The output port
|
|
_port: count;
|
|
};
|
|
|
|
# The restAPI documentation can be found at
|
|
# https://media.readthedocs.org/pdf/ryu/latest/ryu.pdf
|
|
# on page 278-299
|
|
type ryu_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;
|
|
buffer_id: count &optional;
|
|
flags: count &optional;
|
|
match: Openflow::ofp_match;
|
|
actions: vector of ryu_flow_action_output;
|
|
};
|
|
|
|
# register the ryu openflow plugin flow_mod function
|
|
hook register_openflow_plugin() {
|
|
register_openflow_mod_func(
|
|
function(dpid: count, flow_mod: ofp_flow_mod): bool {
|
|
# 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) {
|
|
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);
|
|
return F;
|
|
}
|
|
}
|
|
# Generate our ryu_flow_mod record for the restAPI call.
|
|
local _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=flow_mod$match,
|
|
$actions=_flow_actions
|
|
);
|
|
# Type of the command
|
|
local command_type: string;
|
|
switch(flow_mod$command) {
|
|
case OFPFC_ADD:
|
|
command_type = "add";
|
|
break;
|
|
case OFPFC_DELETE:
|
|
command_type = "delete";
|
|
break;
|
|
default:
|
|
print fmt("Error: command type '%s' not available", flow_mod$command);
|
|
return F;
|
|
}
|
|
# Create the ActiveHTTP request and convert the record to a ryu restAPI 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);
|
|
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;
|
|
}
|
|
);
|
|
}
|