-
Notifications
You must be signed in to change notification settings - Fork 11
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
285 additions
and
18 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
UncommunicativeModuleName: | ||
accept: ['Pio::Hello13'] |
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,28 @@ | ||
Feature: Pio::Hello13.read | ||
Scenario: hello13_no_version_bitmap.raw | ||
Given a packet data file "hello13_no_version_bitmap.raw" | ||
When I try to parse the file with "Hello13" class | ||
Then it should finish successfully | ||
And the parsed data have the following field and value: | ||
| field | value | | ||
| class | Pio::Hello13 | | ||
| ofp_version | 4 | | ||
| message_type | 0 | | ||
| message_length | 8 | | ||
| transaction_id | 0 | | ||
| xid | 0 | | ||
| supported_versions | [] | | ||
|
||
Scenario: hello13_version_bitmap.raw | ||
Given a packet data file "hello13_version_bitmap.raw" | ||
When I try to parse the file with "Hello13" class | ||
Then it should finish successfully | ||
And the parsed data have the following field and value: | ||
| field | value | | ||
| class | Pio::Hello13 | | ||
| ofp_version | 4 | | ||
| message_type | 0 | | ||
| message_length | 16 | | ||
| transaction_id | 0 | | ||
| xid | 0 | | ||
| supported_versions | [:open_flow10, :open_flow13] | |
Binary file not shown.
Binary file not shown.
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,113 @@ | ||
require 'bindata' | ||
require 'pio/open_flow/transaction_id' | ||
require 'pio/parse_error' | ||
|
||
module Pio | ||
# OpenFlow 1.3 Hello message parser and generator | ||
class Hello13 | ||
# ofp_hello_elem_header and value | ||
class Element < BinData::Record | ||
VERSION_BITMAP = 1 | ||
|
||
endian :big | ||
|
||
uint16 :element_type | ||
uint16 :element_length | ||
choice :element_value, selection: :chooser do | ||
string 'unknown', read_length: -> { element_length - 4 } | ||
uint32 'version_bitmap' | ||
end | ||
|
||
def version_bitmap? | ||
element_type == VERSION_BITMAP | ||
end | ||
|
||
private | ||
|
||
def chooser | ||
version_bitmap? ? 'version_bitmap' : 'unknown' | ||
end | ||
end | ||
|
||
# OpenFlow 1.3 Hello message format | ||
class Format < BinData::Record | ||
OFP_VERSION = 4 | ||
|
||
endian :big | ||
|
||
uint8 :ofp_version, initial_value: OFP_VERSION | ||
virtual assert: -> { ofp_version == OFP_VERSION } | ||
uint8 :message_type | ||
uint16 :message_length, initial_value: :hello_message_length | ||
transaction_id :transaction_id | ||
array :elements, type: :element, read_until: :eof | ||
|
||
def xid | ||
transaction_id | ||
end | ||
|
||
def supported_versions | ||
supported_versions_list.map do |each| | ||
"open_flow1#{each - 1}".to_sym | ||
end | ||
end | ||
|
||
alias_method :to_binary, :to_binary_s | ||
|
||
private | ||
|
||
def hello_message_length | ||
8 + if elements.empty? | ||
0 | ||
else | ||
elements.length * 4 + 4 | ||
end | ||
end | ||
|
||
def supported_versions_list | ||
(1..32).each_with_object([]) do |each, result| | ||
result << each if (version_bitmap >> each & 1) == 1 | ||
end | ||
end | ||
|
||
def version_bitmap | ||
bitmap = elements.select(&:version_bitmap?).first | ||
bitmap ? bitmap.element_value : 0 | ||
end | ||
end | ||
|
||
# Hello13.new argument | ||
class Options | ||
def initialize(user_attrs) | ||
@attrs = { elements: [{ element_type: 1, | ||
element_length: 8, | ||
element_value: 16 }] } | ||
@attrs = @attrs.merge(user_attrs) | ||
@attrs[:transaction_id] = @attrs.fetch(:xid) if @attrs.key?(:xid) | ||
unknown_keywords = @attrs.keys - [:transaction_id, :xid, :elements] | ||
return if unknown_keywords.empty? | ||
fail "Unknown keyword: #{unknown_keywords.first}" | ||
end | ||
|
||
def to_h | ||
@attrs | ||
end | ||
end | ||
|
||
def self.read(raw_data) | ||
allocate.tap do |message| | ||
message.instance_variable_set(:@format, Format.read(raw_data)) | ||
end | ||
rescue BinData::ValidityError | ||
raise Pio::ParseError, 'Invalid Hello 1.3 message.' | ||
end | ||
|
||
def initialize(attrs = {}) | ||
@format = Format.new(Options.new(attrs).to_h) | ||
end | ||
|
||
def method_missing(method, *args, &block) | ||
@format.__send__ method, *args, &block | ||
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,25 @@ | ||
require 'bindata' | ||
require 'pio/monkey_patch/integer' | ||
|
||
module Pio | ||
module OpenFlow | ||
# Transaction ID (uint32) | ||
class TransactionId < BinData::Primitive | ||
endian :big | ||
|
||
uint32 :xid | ||
|
||
def set(value) | ||
unless value.unsigned_32bit? | ||
fail(ArgumentError, | ||
'Transaction ID should be an unsigned 32-bit integer.') | ||
end | ||
self.xid = value | ||
end | ||
|
||
def get | ||
xid | ||
end | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
require 'pio/hello13' | ||
|
||
describe Pio::Hello13 do | ||
describe '.read' do | ||
When(:result) { Pio::Hello13.read(binary) } | ||
|
||
context 'with a hello message (no version bitmap)' do | ||
Given(:binary) { [4, 0, 0, 8, 0, 0, 0, 0].pack('C*') } | ||
|
||
Then { result.class == Pio::Hello13 } | ||
Then { result.ofp_version == 4 } | ||
Then { result.message_type == 0 } | ||
Then { result.message_length == 8 } | ||
Then { result.transaction_id == 0 } | ||
Then { result.xid == 0 } | ||
Then { result.supported_versions.empty? } | ||
end | ||
|
||
context 'with a hello message' do | ||
Given(:binary) do | ||
[4, 0, 0, 16, 0, 0, 0, 0, 0, 1, 0, 8, 0, 0, 0, 18].pack('C*') | ||
end | ||
|
||
Then { result.class == Pio::Hello13 } | ||
Then { result.ofp_version == 4 } | ||
Then { result.message_type == 0 } | ||
Then { result.message_length == 16 } | ||
Then { result.transaction_id == 0 } | ||
Then { result.xid == 0 } | ||
Then { result.supported_versions == [:open_flow10, :open_flow13] } | ||
end | ||
|
||
context 'with a hello message (OpenFlow 1.0)' do | ||
Given(:binary) { [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') } | ||
|
||
Then { result == Failure(Pio::ParseError, 'Invalid Hello 1.3 message.') } | ||
end | ||
end | ||
|
||
describe '.new' do | ||
context 'with no arguments' do | ||
When(:result) { Pio::Hello13.new } | ||
|
||
Then { result.ofp_version == 4 } | ||
Then { result.message_type == 0 } | ||
Then { result.message_length == 16 } | ||
Then { result.transaction_id == 0 } | ||
Then { result.xid == 0 } | ||
Then { result.supported_versions == [:open_flow13] } | ||
Then do | ||
result.to_binary == | ||
[4, 0, 0, 16, 0, 0, 0, 0, 0, 1, 0, 8, 0, 0, 0, 16].pack('C*') | ||
end | ||
end | ||
|
||
context 'with transaction_id: 123' do | ||
When(:result) { Pio::Hello13.new(transaction_id: 123) } | ||
|
||
Then { result.ofp_version == 4 } | ||
Then { result.message_type == 0 } | ||
Then { result.message_length == 16 } | ||
Then { result.transaction_id == 123 } | ||
Then { result.xid == 123 } | ||
Then { result.supported_versions == [:open_flow13] } | ||
Then do | ||
result.to_binary == | ||
[4, 0, 0, 16, 0, 0, 0, 123, 0, 1, 0, 8, 0, 0, 0, 16].pack('C*') | ||
end | ||
end | ||
|
||
context 'with xid: 123' do | ||
When(:result) { Pio::Hello13.new(xid: 123) } | ||
|
||
Then { result.ofp_version == 4 } | ||
Then { result.message_type == 0 } | ||
Then { result.message_length == 16 } | ||
Then { result.transaction_id == 123 } | ||
Then { result.xid == 123 } | ||
Then { result.supported_versions == [:open_flow13] } | ||
Then do | ||
result.to_binary == | ||
[4, 0, 0, 16, 0, 0, 0, 123, 0, 1, 0, 8, 0, 0, 0, 16].pack('C*') | ||
end | ||
end | ||
|
||
context 'with xid: -1' do | ||
When(:result) { Pio::Hello13.new(xid: -1) } | ||
|
||
Then do | ||
result == | ||
Failure(ArgumentError, | ||
'Transaction ID should be an unsigned 32-bit integer.') | ||
end | ||
end | ||
|
||
context 'with xid: 2**32' do | ||
When(:result) { Pio::Hello13.new(xid: 2**32) } | ||
|
||
Then do | ||
result == | ||
Failure(ArgumentError, | ||
'Transaction ID should be an unsigned 32-bit integer.') | ||
end | ||
end | ||
|
||
context 'with invalid_keyword: :foo' do | ||
When(:result) { Pio::Hello13.new(invalid_keyword: :foo) } | ||
|
||
Then do | ||
result == Failure(RuntimeError, 'Unknown keyword: invalid_keyword') | ||
end | ||
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