Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
251 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
Feature: Pio::PacketOut | ||
Background: | ||
Given I use OpenFlow 1.3 | ||
|
||
Scenario: new | ||
When I try to create an OpenFlow message with: | ||
""" | ||
Pio::PacketOut.new | ||
""" | ||
Then it should finish successfully | ||
And the message have the following fields and values: | ||
| field | value | | ||
| class | Pio::PacketOut | | ||
| ofp_version | 4 | | ||
| message_type | 13 | | ||
| message_length | 24 | | ||
| transaction_id | 0 | | ||
| xid | 0 | | ||
| buffer_id | :no_buffer | | ||
| in_port | 0 | | ||
| actions_length | 0 | | ||
| raw_data.length | 0 | | ||
|
||
Scenario: new (actions = SendOutPort(1), raw_data = ARP Request) | ||
When I try to create an OpenFlow message with: | ||
""" | ||
data_dump = [ | ||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xac, 0x5d, 0x10, 0x31, 0x37, | ||
0x79, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, | ||
0xac, 0x5d, 0x10, 0x31, 0x37, 0x79, 0xc0, 0xa8, 0x02, 0xfe, 0xff, | ||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xa8, 0x02, 0x05, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00 | ||
].pack('C*') | ||
Pio::PacketOut.new(raw_data: data_dump, actions: Pio::SendOutPort.new(1)) | ||
""" | ||
Then it should finish successfully | ||
And the message have the following fields and values: | ||
| field | value | | ||
| class | Pio::PacketOut | | ||
| ofp_version | 4 | | ||
| message_type | 13 | | ||
| message_length | 100 | | ||
| transaction_id | 0 | | ||
| xid | 0 | | ||
| buffer_id | :no_buffer | | ||
| in_port | 0 | | ||
| actions_length | 16 | | ||
| raw_data.length | 60 | | ||
| data.class | Pio::Arp::Request | | ||
| destination_mac | ff:ff:ff:ff:ff:ff | | ||
| source_mac | ac:5d:10:31:37:79 | | ||
| ether_type | 2054 | | ||
| hardware_type | 1 | | ||
| protocol_type | 2048 | | ||
| hardware_length | 6 | | ||
| protocol_length | 4 | | ||
| operation | 1 | | ||
| sender_hardware_address | ac:5d:10:31:37:79 | | ||
| sender_protocol_address | 192.168.2.254 | | ||
| target_hardware_address | ff:ff:ff:ff:ff:ff | | ||
| target_protocol_address | 192.168.2.5 | | ||
|
||
Scenario: read | ||
When I try to parse a file named "open_flow13/packet_out.raw" with "PacketOut" class | ||
Then it should finish successfully | ||
And the message have the following fields and values: | ||
| field | value | | ||
| class | Pio::PacketOut | | ||
| ofp_version | 4 | | ||
| message_type | 13 | | ||
| message_length | 100 | | ||
| transaction_id | 123 | | ||
| xid | 123 | | ||
| buffer_id | :no_buffer | | ||
| in_port | :controller | | ||
| actions_length | 16 | | ||
| actions.first.class | Pio::SendOutPort | | ||
| actions.first.port | 1 | | ||
| actions.first.max_length | :no_buffer | | ||
| raw_data.length | 60 | | ||
| data.class | Pio::Arp::Request | | ||
| destination_mac | ff:ff:ff:ff:ff:ff | | ||
| source_mac | ac:5d:10:31:37:79 | | ||
| ether_type | 2054 | | ||
| hardware_type | 1 | | ||
| protocol_type | 2048 | | ||
| hardware_length | 6 | | ||
| protocol_length | 4 | | ||
| operation | 1 | | ||
| sender_hardware_address | ac:5d:10:31:37:79 | | ||
| sender_protocol_address | 192.168.2.254 | | ||
| target_hardware_address | ff:ff:ff:ff:ff:ff | | ||
| target_protocol_address | 192.168.2.5 | | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
require 'bindata' | ||
|
||
module Pio | ||
# Actions not yet implemented. | ||
class UnsupportedAction < BinData::Record | ||
endian :big | ||
|
||
uint16 :action_type | ||
uint16 :action_length | ||
end | ||
|
||
# Actions list of actions-apply instruction. | ||
class Actions < BinData::Primitive | ||
mandatory_parameter :length | ||
|
||
endian :big | ||
|
||
string :binary, read_length: :length | ||
|
||
def set(value) | ||
self.binary = [value].flatten.map(&:to_binary).join | ||
end | ||
|
||
# rubocop:disable MethodLength | ||
def get | ||
actions = [] | ||
tmp = binary | ||
while tmp.length > 0 | ||
action = case BinData::Uint16be.read(tmp) | ||
when 0 | ||
SendOutPort.read(tmp) | ||
else | ||
UnsupportedAction.read(tmp) | ||
end | ||
tmp = tmp[action.action_length..-1] | ||
actions << action | ||
end | ||
actions | ||
end | ||
# rubocop:enable MethodLength | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module Pio | ||
# Buffered packet to apply to, or :no_buffer. | ||
class BufferId < BinData::Primitive | ||
NO_BUFFER = 0xffffffff | ||
|
||
endian :big | ||
uint32 :buffer_id, initial_value: NO_BUFFER | ||
|
||
def get | ||
(buffer_id == NO_BUFFER) ? :no_buffer : buffer_id | ||
end | ||
|
||
def set(value) | ||
self.buffer_id = (value == :no_buffer ? NO_BUFFER : value) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
require 'bindata' | ||
require 'pio/open_flow13/actions' | ||
require 'pio/open_flow13/buffer_id' | ||
|
||
# Base module. | ||
module Pio | ||
remove_const :PacketOut | ||
|
||
# OpenFlow 1.3 PacketOut message parser and generator | ||
class PacketOut | ||
# Packet's input port or :controller | ||
class InPort < BinData::Primitive | ||
CONTROLLER = 0xfffffffd | ||
|
||
endian :big | ||
uint32 :in_port | ||
|
||
def get | ||
(in_port == CONTROLLER) ? :controller : in_port | ||
end | ||
|
||
def set(value) | ||
self.in_port = (value == :controller ? NO_CONTROLLER : value) | ||
end | ||
end | ||
|
||
# OpenFlow 1.3 PacketOut message body | ||
class Body < BinData::Record | ||
endian :big | ||
|
||
buffer_id :buffer_id | ||
in_port :in_port | ||
uint16 :actions_length, initial_value: -> { actions.binary.length } | ||
string :padding, length: 6 | ||
actions :actions, length: :actions_length | ||
string :raw_data, read_length: -> { message_length - 24 - actions_length } | ||
|
||
def length | ||
10 + padding.length + actions_length + raw_data.length | ||
end | ||
|
||
def data | ||
@data ||= Pio::Parser.read(raw_data) | ||
end | ||
|
||
def method_missing(method, *args) | ||
data.__send__(method, *args).snapshot | ||
end | ||
end | ||
|
||
# OpenFlow 1.3 PacketOut message body | ||
class Format < BinData::Record | ||
extend Forwardable | ||
|
||
endian :big | ||
|
||
open_flow_header :open_flow_header, | ||
ofp_version_value: 4, message_type_value: 13 | ||
body :body | ||
|
||
def_delegators :open_flow_header, :ofp_version | ||
def_delegators :open_flow_header, :message_type | ||
def_delegators :open_flow_header, :message_length | ||
def_delegators :open_flow_header, :transaction_id | ||
def_delegator :open_flow_header, :transaction_id, :xid | ||
|
||
def method_missing(method, *args, &block) | ||
body.__send__ method, *args, &block | ||
end | ||
end | ||
|
||
def self.read(raw_data) | ||
allocate.tap do |message| | ||
message.instance_variable_set(:@format, Format.read(raw_data)) | ||
end | ||
end | ||
|
||
def initialize(user_attrs = {}) | ||
header_attrs = OpenFlowHeader::Options.parse(user_attrs) | ||
body_attrs = { actions: user_attrs[:actions], | ||
raw_data: user_attrs[:raw_data] } | ||
@format = Format.new(open_flow_header: header_attrs, | ||
body: body_attrs) | ||
end | ||
|
||
def method_missing(method, *args, &block) | ||
@format.__send__ method, *args, &block | ||
end | ||
end | ||
end |