pio 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|