pio 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +56 -22
- data/examples/dhcp_new.rb +22 -18
- data/examples/features_new.rb +14 -0
- data/examples/features_read.rb +4 -0
- data/features/arp_read.feature +4 -4
- data/features/dhcp_read.feature +2 -2
- data/features/echo_read.feature +5 -0
- data/features/features_read.feature +10 -0
- data/features/hello_read.feature +5 -0
- data/features/icmp_read.feature +2 -2
- data/features/lldp_read.feature +4 -4
- data/features/{pcap → packet_data}/arp-storm.pcap +0 -0
- data/features/{pcap → packet_data}/arp.pcap +0 -0
- data/features/{pcap → packet_data}/dhcp.pcap +0 -0
- data/features/packet_data/echo.raw +0 -0
- data/features/packet_data/features_reply.raw +0 -0
- data/features/packet_data/features_request.raw +0 -0
- data/features/packet_data/hello.raw +0 -0
- data/features/{pcap → packet_data}/icmp.pcap +0 -0
- data/features/{pcap → packet_data}/lldp.detailed.pcap +0 -0
- data/features/{pcap → packet_data}/lldp.minimal.pcap +0 -0
- data/features/step_definitions/packet_data_steps.rb +32 -0
- data/features/step_definitions/pending_steps.rb +5 -0
- data/lib/pio.rb +1 -0
- data/lib/pio/arp.rb +1 -1
- data/lib/pio/arp/{frame.rb → format.rb} +2 -2
- data/lib/pio/arp/message.rb +2 -2
- data/lib/pio/dhcp/dhcp_field.rb +3 -3
- data/lib/pio/dhcp/frame.rb +6 -6
- data/lib/pio/dhcp/optional_tlv.rb +3 -3
- data/lib/pio/echo.rb +4 -11
- data/lib/pio/echo/format.rb +5 -5
- data/lib/pio/echo/message.rb +13 -4
- data/lib/pio/echo/reply.rb +29 -0
- data/lib/pio/echo/request.rb +29 -0
- data/lib/pio/features.rb +18 -0
- data/lib/pio/features/format.rb +18 -0
- data/lib/pio/features/message.rb +14 -0
- data/lib/pio/features/reply.rb +73 -0
- data/lib/pio/features/request.rb +63 -0
- data/lib/pio/hello.rb +40 -9
- data/lib/pio/icmp.rb +1 -1
- data/lib/pio/icmp/{frame.rb → format.rb} +2 -2
- data/lib/pio/icmp/message.rb +2 -2
- data/lib/pio/icmp/request.rb +30 -14
- data/lib/pio/message_type_selector.rb +4 -7
- data/lib/pio/type/ethernet_header.rb +0 -2
- data/lib/pio/type/ipv4_header.rb +0 -1
- data/lib/pio/type/open_flow.rb +34 -0
- data/lib/pio/type/udp_header.rb +0 -1
- data/lib/pio/version.rb +1 -1
- data/pio.gemspec +2 -2
- data/spec/pio/dhcp/ack_spec.rb +1 -1
- data/spec/pio/dhcp_spec.rb +2 -2
- data/spec/pio/echo/reply_spec.rb +69 -4
- data/spec/pio/echo/request_spec.rb +48 -10
- data/spec/pio/echo_spec.rb +8 -0
- data/spec/pio/features/reply_spec.rb +30 -0
- data/spec/pio/features/request_spec.rb +70 -0
- data/spec/pio/features_spec.rb +78 -0
- data/spec/pio/hello_spec.rb +35 -6
- data/spec/spec_helper.rb +3 -0
- metadata +70 -40
- data/features/step_definitions/pcap_steps.rb +0 -18
data/lib/pio/echo.rb
CHANGED
@@ -3,23 +3,16 @@
|
|
3
3
|
require 'pio/echo/format'
|
4
4
|
require 'pio/echo/reply'
|
5
5
|
require 'pio/echo/request'
|
6
|
+
require 'pio/message_type_selector'
|
6
7
|
|
7
8
|
module Pio
|
8
9
|
# OpenFlow Echo Request and Reply message parser.
|
9
10
|
class Echo
|
11
|
+
extend MessageTypeSelector
|
12
|
+
|
10
13
|
REQUEST = 2
|
11
14
|
REPLY = 3
|
12
15
|
|
13
|
-
|
14
|
-
echo = Echo::Format.read(raw_data)
|
15
|
-
case echo.message_type
|
16
|
-
when REQUEST
|
17
|
-
Echo::Request.create_from(echo)
|
18
|
-
when REPLY
|
19
|
-
Echo::Reply.create_from(echo)
|
20
|
-
else
|
21
|
-
fail 'Unknown Echo message type.'
|
22
|
-
end
|
23
|
-
end
|
16
|
+
message_type REQUEST => Request, REPLY => Reply
|
24
17
|
end
|
25
18
|
end
|
data/lib/pio/echo/format.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'bindata'
|
4
|
+
require 'pio/type/open_flow'
|
4
5
|
|
5
6
|
module Pio
|
6
7
|
class Echo
|
7
8
|
# OpenFlow 1.0 Echo message format.
|
8
9
|
class Format < BinData::Record
|
10
|
+
extend Type::OpenFlow
|
11
|
+
|
9
12
|
endian :big
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
uint16 :message_length, value: -> { 8 + data.length }
|
14
|
-
uint32 :transaction_id, initial_value: 0
|
15
|
-
string :data
|
14
|
+
openflow_header
|
15
|
+
string :body
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/lib/pio/echo/message.rb
CHANGED
@@ -14,7 +14,7 @@ module Pio
|
|
14
14
|
def_delegators :@echo, :message_length
|
15
15
|
def_delegators :@echo, :transaction_id
|
16
16
|
def_delegator :@echo, :transaction_id, :xid
|
17
|
-
|
17
|
+
def_delegator :@echo, :body, :data
|
18
18
|
def_delegator :@echo, :to_binary_s, :to_binary
|
19
19
|
|
20
20
|
def self.create_from(echo)
|
@@ -24,15 +24,24 @@ module Pio
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def initialize(message_type, user_options = {})
|
27
|
-
|
28
|
-
|
27
|
+
if user_options.respond_to?(:to_i)
|
28
|
+
@options = { transaction_id: user_options.to_i,
|
29
|
+
message_type: message_type }
|
30
|
+
elsif user_options.respond_to?(:[])
|
31
|
+
@options = user_options.dup.merge(message_type: message_type)
|
32
|
+
handle_user_hash_options
|
33
|
+
else
|
34
|
+
fail TypeError
|
35
|
+
end
|
29
36
|
@echo = Format.new(@options)
|
30
37
|
end
|
31
38
|
|
32
39
|
private
|
33
40
|
|
34
|
-
def
|
41
|
+
def handle_user_hash_options
|
42
|
+
@options[:body] = @options[:data]
|
35
43
|
@options[:transaction_id] ||= @options[:xid]
|
44
|
+
@options[:transaction_id] = 0 unless @options[:transaction_id]
|
36
45
|
end
|
37
46
|
end
|
38
47
|
end
|
data/lib/pio/echo/reply.rb
CHANGED
@@ -8,6 +8,35 @@ module Pio
|
|
8
8
|
class Echo
|
9
9
|
# OpenFlow 1.0 Echo Reply message.
|
10
10
|
class Reply < Message
|
11
|
+
# Creates an EchoReply OpenFlow message. This message can be
|
12
|
+
# used to measure the bandwidth of a controller/switch
|
13
|
+
# connection as well as to verify its liveness.
|
14
|
+
#
|
15
|
+
# @overload initialize()
|
16
|
+
# @example
|
17
|
+
# Pio::Echo::Reply.new
|
18
|
+
#
|
19
|
+
# @overload initialize(transaction_id)
|
20
|
+
# @example
|
21
|
+
# Pio::Echo::Reply.new(123)
|
22
|
+
# @param [Number] transaction_id
|
23
|
+
# An unsigned 32-bit integer number associated with this
|
24
|
+
# message.
|
25
|
+
#
|
26
|
+
# @overload initialize(user_options)
|
27
|
+
# @example
|
28
|
+
# Pio::Echo::Reply.new(
|
29
|
+
# transaction_id: transaction_id,
|
30
|
+
# user_data: 'Thu Aug 25 13:09:00 +0900 2011'
|
31
|
+
# )
|
32
|
+
# @param [Hash] user_options The options to create a message with.
|
33
|
+
# @option user_options [Number] :transaction_id
|
34
|
+
# @option user_options [Number] :xid An alias to transaction_id.
|
35
|
+
# @option user_options [String] :user_data
|
36
|
+
# The user data field specified as a String may be a message
|
37
|
+
# timestamp to check latency, various lengths to measure
|
38
|
+
# bandwidth or zero-size(nil) to verify liveness between the
|
39
|
+
# switch and controller.
|
11
40
|
def initialize(user_options = {})
|
12
41
|
super REPLY, user_options
|
13
42
|
end
|
data/lib/pio/echo/request.rb
CHANGED
@@ -8,6 +8,35 @@ module Pio
|
|
8
8
|
class Echo
|
9
9
|
# OpenFlow 1.0 Echo Request message.
|
10
10
|
class Request < Message
|
11
|
+
# Creates an EchoRequest OpenFlow message. This message can be
|
12
|
+
# used to measure the bandwidth of a controller/switch
|
13
|
+
# connection as well as to verify its liveness.
|
14
|
+
#
|
15
|
+
# @overload initialize()
|
16
|
+
# @example
|
17
|
+
# Pio::Echo::Request.new
|
18
|
+
#
|
19
|
+
# @overload initialize(transaction_id)
|
20
|
+
# @example
|
21
|
+
# Pio::Echo::Request.new(123)
|
22
|
+
# @param [Number] transaction_id
|
23
|
+
# An unsigned 32-bit integer number associated with this
|
24
|
+
# message.
|
25
|
+
#
|
26
|
+
# @overload initialize(user_options)
|
27
|
+
# @example
|
28
|
+
# Pio::Echo::Request.new(
|
29
|
+
# transaction_id: transaction_id,
|
30
|
+
# user_data: 'Thu Aug 25 13:09:00 +0900 2011'
|
31
|
+
# )
|
32
|
+
# @param [Hash] user_options The options to create a message with.
|
33
|
+
# @option user_options [Number] :transaction_id
|
34
|
+
# @option user_options [Number] :xid An alias to transaction_id.
|
35
|
+
# @option user_options [String] :user_data
|
36
|
+
# The user data field specified as a String may be a message
|
37
|
+
# timestamp to check latency, various lengths to measure
|
38
|
+
# bandwidth or zero-size(nil) to verify liveness between the
|
39
|
+
# switch and controller.
|
11
40
|
def initialize(user_options = {})
|
12
41
|
super REQUEST, user_options
|
13
42
|
end
|
data/lib/pio/features.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'pio/features/format'
|
4
|
+
require 'pio/features/reply'
|
5
|
+
require 'pio/features/request'
|
6
|
+
require 'pio/message_type_selector'
|
7
|
+
|
8
|
+
module Pio
|
9
|
+
# OpenFlow 1.0 Features messages
|
10
|
+
class Features
|
11
|
+
extend MessageTypeSelector
|
12
|
+
|
13
|
+
REQUEST = 5
|
14
|
+
REPLY = 6
|
15
|
+
|
16
|
+
message_type REQUEST => Request, REPLY => Reply
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'bindata'
|
4
|
+
require 'pio/type/open_flow'
|
5
|
+
|
6
|
+
module Pio
|
7
|
+
class Features
|
8
|
+
# OpenFlow 1.0 Features message format.
|
9
|
+
class Format < BinData::Record
|
10
|
+
extend Type::OpenFlow
|
11
|
+
|
12
|
+
endian :big
|
13
|
+
|
14
|
+
openflow_header
|
15
|
+
string :body, read_length: -> { message_length - 8 }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Pio
|
4
|
+
class Features
|
5
|
+
# Base class of Features request and reply.
|
6
|
+
class Message
|
7
|
+
def self.create_from(features)
|
8
|
+
message = allocate
|
9
|
+
message.instance_variable_set :@features, features
|
10
|
+
message
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'bindata'
|
4
|
+
require 'forwardable'
|
5
|
+
require 'pio/features/message'
|
6
|
+
|
7
|
+
module Pio
|
8
|
+
# OpenFlow 1.0 Features messages
|
9
|
+
class Features
|
10
|
+
# OpenFlow 1.0 Features Reply message
|
11
|
+
class Reply < Message
|
12
|
+
# Message body of Features Reply
|
13
|
+
class Body < BinData::Record
|
14
|
+
endian :big
|
15
|
+
|
16
|
+
uint64 :datapath_id
|
17
|
+
uint32 :n_buffers
|
18
|
+
uint8 :n_tables
|
19
|
+
uint24 :padding
|
20
|
+
uint32 :capabilities
|
21
|
+
uint32 :actions
|
22
|
+
array :ports, type: :phy_port, read_until: :eof
|
23
|
+
end
|
24
|
+
|
25
|
+
extend Forwardable
|
26
|
+
|
27
|
+
def_delegators :@features, :version
|
28
|
+
def_delegators :@features, :message_type
|
29
|
+
def_delegators :@features, :message_length
|
30
|
+
def_delegators :@features, :transaction_id
|
31
|
+
def_delegator :@features, :transaction_id, :xid
|
32
|
+
def_delegators :@features, :body
|
33
|
+
|
34
|
+
def initialize(user_options = {})
|
35
|
+
@options = user_options.dup.merge(datapath_id: user_options[:dpid])
|
36
|
+
body = Body.new(@options)
|
37
|
+
@features = Format.new(@options.merge(message_type: 6,
|
38
|
+
body: body.to_binary_s))
|
39
|
+
end
|
40
|
+
|
41
|
+
def datapath_id
|
42
|
+
@body ||= Body.read(@features.body)
|
43
|
+
@body.datapath_id
|
44
|
+
end
|
45
|
+
alias_method :dpid, :datapath_id
|
46
|
+
|
47
|
+
def n_buffers
|
48
|
+
@body ||= Body.read(@features.body)
|
49
|
+
@body.n_buffers
|
50
|
+
end
|
51
|
+
|
52
|
+
def n_tables
|
53
|
+
@body ||= Body.read(@features.body)
|
54
|
+
@body.n_tables
|
55
|
+
end
|
56
|
+
|
57
|
+
def capabilities
|
58
|
+
@body ||= Body.read(@features.body)
|
59
|
+
@body.capabilities
|
60
|
+
end
|
61
|
+
|
62
|
+
def actions
|
63
|
+
@body ||= Body.read(@features.body)
|
64
|
+
@body.actions
|
65
|
+
end
|
66
|
+
|
67
|
+
def ports
|
68
|
+
@body ||= Body.read(@features.body)
|
69
|
+
@body.ports
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'pio/features/message'
|
5
|
+
|
6
|
+
module Pio
|
7
|
+
# OpenFlow 1.0 Features messages
|
8
|
+
class Features
|
9
|
+
# OpenFlow 1.0 Features Request message
|
10
|
+
class Request < Message
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def_delegators :@features, :version
|
14
|
+
def_delegators :@features, :message_type
|
15
|
+
def_delegators :@features, :message_length
|
16
|
+
def_delegators :@features, :transaction_id
|
17
|
+
def_delegator :@features, :transaction_id, :xid
|
18
|
+
def_delegators :@features, :body
|
19
|
+
def_delegator :@features, :to_binary_s, :to_binary
|
20
|
+
|
21
|
+
# Creates a Features Request OpenFlow message.
|
22
|
+
#
|
23
|
+
# @overload initialize()
|
24
|
+
# @example
|
25
|
+
# Pio::Features::Request.new
|
26
|
+
#
|
27
|
+
# @overload initialize(transaction_id)
|
28
|
+
# @example
|
29
|
+
# Pio::Features::Request.new(123)
|
30
|
+
# @param [Number] transaction_id
|
31
|
+
# An unsigned 32-bit integer number associated with this
|
32
|
+
# message.
|
33
|
+
#
|
34
|
+
# @overload initialize(user_options)
|
35
|
+
# @example
|
36
|
+
# Pio::Features::Request.new(transaction_id: 123)
|
37
|
+
# Pio::Features::Request.new(xid: 123)
|
38
|
+
# @param [Hash] user_options
|
39
|
+
# The options to create a message with.
|
40
|
+
# @option user_options [Number] :transaction_id
|
41
|
+
# @option user_options [Number] :xid An alias to transaction_id.
|
42
|
+
def initialize(user_options = {})
|
43
|
+
if user_options.respond_to?(:to_i)
|
44
|
+
@options = { transaction_id: user_options.to_i,
|
45
|
+
message_type: 5 }
|
46
|
+
elsif user_options.respond_to?(:[])
|
47
|
+
@options = user_options.dup.merge(message_type: 5)
|
48
|
+
handle_user_hash_options
|
49
|
+
else
|
50
|
+
fail TypeError
|
51
|
+
end
|
52
|
+
@features = Format.new(@options)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def handle_user_hash_options
|
58
|
+
@options[:transaction_id] ||= @options[:xid]
|
59
|
+
@options[:transaction_id] = 0 unless @options[:transaction_id]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/pio/hello.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'English'
|
3
4
|
require 'forwardable'
|
4
5
|
require 'pio/hello/format'
|
5
6
|
|
@@ -16,22 +17,52 @@ module Pio
|
|
16
17
|
def_delegators :@data, :body
|
17
18
|
def_delegator :@data, :to_binary_s, :to_binary
|
18
19
|
|
20
|
+
# Parses +raw_data+ binary string into a Hello message object.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# Pio::Hello.read("\x01\x00\x00\b\x00\x00\x00\x00")
|
24
|
+
# @return [Pio::Hello]
|
19
25
|
def self.read(raw_data)
|
20
26
|
hello = allocate
|
21
|
-
|
27
|
+
begin
|
28
|
+
hello.instance_variable_set :@data, Format.read(raw_data)
|
29
|
+
rescue BinData::ValidityError
|
30
|
+
raise ParseError, $ERROR_INFO.message
|
31
|
+
end
|
22
32
|
hello
|
23
33
|
end
|
24
34
|
|
35
|
+
# Creates a Hello OpenFlow message.
|
36
|
+
#
|
37
|
+
# @overload initialize()
|
38
|
+
# @example
|
39
|
+
# Pio::Hello.new
|
40
|
+
#
|
41
|
+
# @overload initialize(transaction_id)
|
42
|
+
# @example
|
43
|
+
# Pio::Hello.new(123)
|
44
|
+
# @param [Number] transaction_id
|
45
|
+
# An unsigned 32-bit integer number associated with this
|
46
|
+
# message.
|
47
|
+
#
|
48
|
+
# @overload initialize(user_options)
|
49
|
+
# @example
|
50
|
+
# Pio::Hello.new(transaction_id: 123)
|
51
|
+
# Pio::Hello.new(xid: 123)
|
52
|
+
# @param [Hash] user_options The options to create a message with.
|
53
|
+
# @option user_options [Number] :transaction_id
|
54
|
+
# @option user_options [Number] :xid An alias to transaction_id.
|
25
55
|
def initialize(user_options = {})
|
26
|
-
|
27
|
-
|
56
|
+
if user_options.respond_to?(:to_i)
|
57
|
+
@options = { transaction_id: user_options.to_i }
|
58
|
+
elsif user_options.respond_to?(:[])
|
59
|
+
@options = user_options.dup
|
60
|
+
@options[:transaction_id] ||= @options[:xid]
|
61
|
+
@options[:transaction_id] = 0 unless @options[:transaction_id]
|
62
|
+
else
|
63
|
+
fail TypeError
|
64
|
+
end
|
28
65
|
@data = Format.new(@options)
|
29
66
|
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def handle_option_aliases
|
34
|
-
@options[:transaction_id] ||= @options[:xid]
|
35
|
-
end
|
36
67
|
end
|
37
68
|
end
|
data/lib/pio/icmp.rb
CHANGED
data/lib/pio/icmp/message.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'pio/icmp/
|
3
|
+
require 'pio/icmp/format'
|
4
4
|
require 'forwardable'
|
5
5
|
|
6
6
|
module Pio
|
@@ -42,7 +42,7 @@ module Pio
|
|
42
42
|
|
43
43
|
def initialize(user_options)
|
44
44
|
options = self.class.const_get(:Options).new(user_options)
|
45
|
-
@frame = Icmp::
|
45
|
+
@frame = Icmp::Format.new(options.to_hash)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|