openflow-protocol 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/actions/actions.rb +1 -24
- data/lib/helpers/array_of_subclasses.rb +38 -0
- data/lib/helpers/superclass_base.rb +2 -0
- data/lib/messages/features_reply.rb +2 -2
- data/lib/messages/message.rb +1 -1
- data/lib/messages/port_mod.rb +2 -0
- data/lib/messages/queue_get_config_reply.rb +14 -0
- data/lib/messages/queue_get_config_request.rb +11 -0
- data/lib/{statistics → messages/statistics}/aggregate_statistics_reply.rb +0 -0
- data/lib/{statistics → messages/statistics}/aggregate_statistics_request.rb +0 -0
- data/lib/{statistics → messages/statistics}/description_statistics.rb +0 -0
- data/lib/{statistics → messages/statistics}/flow_statistics_reply.rb +0 -0
- data/lib/{statistics → messages/statistics}/flow_statistics_request.rb +0 -0
- data/lib/{statistics → messages/statistics}/port_statistics_reply.rb +1 -1
- data/lib/{statistics → messages/statistics}/port_statistics_request.rb +1 -1
- data/lib/{statistics → messages/statistics}/queue_statistics_reply.rb +1 -1
- data/lib/{statistics → messages/statistics}/queue_statistics_request.rb +1 -1
- data/lib/{statistics → messages/statistics}/table_statistics.rb +1 -1
- data/lib/{statistics → messages/statistics}/vendor_statistics.rb +0 -0
- data/lib/openflow-protocol/version.rb +1 -1
- data/lib/structs/packet_queue.rb +10 -0
- data/lib/structs/port_number.rb +14 -0
- data/lib/structs/queue_properties/queue_properties.rb +5 -0
- data/lib/structs/queue_properties/queue_property.rb +16 -0
- data/lib/structs/queue_properties/queue_property_min_rate.rb +26 -0
- data/lib/structs/queue_properties/queue_property_none.rb +3 -0
- data/spec/actions/actions_spec.rb +1 -1
- data/spec/messages/barrier_reply_spec.rb +7 -1
- data/spec/messages/barrier_request_spec.rb +7 -1
- data/spec/messages/echo_reply_spec.rb +7 -1
- data/spec/messages/echo_request_spec.rb +7 -1
- data/spec/messages/error_spec.rb +10 -2
- data/spec/messages/features_reply_spec.rb +50 -39
- data/spec/messages/features_request_spec.rb +7 -1
- data/spec/messages/flow_mod_spec.rb +10 -2
- data/spec/messages/flow_removed_spec.rb +10 -2
- data/spec/messages/get_config_reply_spec.rb +10 -2
- data/spec/messages/get_config_request_spec.rb +7 -1
- data/spec/messages/hello_spec.rb +7 -1
- data/spec/messages/packet_in_spec.rb +10 -2
- data/spec/messages/packet_out_spec.rb +10 -2
- data/spec/messages/port_mod_spec.rb +10 -2
- data/spec/messages/port_status_spec.rb +10 -2
- data/spec/messages/queue_get_config_reply_spec.rb +68 -0
- data/spec/messages/queue_get_config_request_spec.rb +40 -0
- data/spec/messages/set_config_spec.rb +10 -2
- data/spec/{statistics → messages/statistics}/aggregate_statistics_reply_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/aggregate_statistics_request_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/description_statistics_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/flow_statistics_reply_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/flow_statistics_request_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/port_statistics_reply_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/port_statistics_request_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/queue_statistics_reply_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/queue_statistics_request_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/table_statistics_spec.rb +0 -0
- data/spec/{statistics → messages/statistics}/vendor_statistics_spec.rb +0 -0
- data/spec/messages/statistics_reply_spec.rb +77 -20
- data/spec/messages/statistics_request_spec.rb +13 -5
- data/spec/messages/vendor_spec.rb +10 -2
- data/spec/structs/packet_queue_spec.rb +37 -0
- data/spec/structs/port_number_spec.rb +19 -0
- data/spec/structs/queue_properties/queue_properties_spec.rb +29 -0
- data/spec/structs/queue_properties/queue_property_min_rate_spec.rb +32 -0
- data/spec/structs/queue_properties/queue_property_none_spec.rb +14 -0
- metadata +55 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b787a021c7be6ba96d78b7f71f9d93676c709bd7
|
4
|
+
data.tar.gz: 80ea8bef3b0e8fbd6783d8fdb35fb278032c9d0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 842cbdc2c9b75e80d1dbb53d853fa6c578bbc8ec05d3db6bb8450fd7be2017fb8586c1ba435410b717979e6fe95171fb8d776677c9b9a8c4a59e65e4f79ec0dc
|
7
|
+
data.tar.gz: b1139123757191b1c60e00866e8543c423e324f70f49ea23e4ee8ee02fbc2ed72b13c1ae891255e6487e4c9c8cf8137028235956fed6baaf3f8dd76a5c44e47d
|
data/lib/actions/actions.rb
CHANGED
@@ -2,27 +2,4 @@ Dir[File.expand_path 'action_*.rb', __dir__].each do |file|
|
|
2
2
|
require file
|
3
3
|
end
|
4
4
|
|
5
|
-
class OFActions <
|
6
|
-
default_parameter length: 0
|
7
|
-
endian :big
|
8
|
-
string :binary, read_length: :length
|
9
|
-
|
10
|
-
def get
|
11
|
-
actions = []
|
12
|
-
tmp = binary
|
13
|
-
until tmp.empty?
|
14
|
-
type_index = BinData::Uint16be.read(tmp)
|
15
|
-
type_str = OFAction::TYPES.fetch(type_index)
|
16
|
-
class_name = 'OFAction' + type_str.to_s.split('_').map(&:capitalize).join
|
17
|
-
klass = Object.const_get class_name
|
18
|
-
action = klass.read(tmp)
|
19
|
-
actions << action
|
20
|
-
tmp = tmp[action.len..-1]
|
21
|
-
end
|
22
|
-
actions
|
23
|
-
end
|
24
|
-
|
25
|
-
def set(value)
|
26
|
-
self.binary = value.map(&:to_binary_s).join
|
27
|
-
end
|
28
|
-
end
|
5
|
+
class OFActions < ArrayOfSubclasses; end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
class ArrayOfSubclasses < BinData::Primitive
|
4
|
+
default_parameter length: 0
|
5
|
+
endian :big
|
6
|
+
string :binary, read_length: :length
|
7
|
+
|
8
|
+
def get
|
9
|
+
items = []
|
10
|
+
tmp = binary
|
11
|
+
until tmp.empty?
|
12
|
+
type_index = BinData::Uint16be.read(tmp)
|
13
|
+
type_str = types.fetch(type_index)
|
14
|
+
class_name = name + type_str.to_s.split('_').map(&:capitalize).join
|
15
|
+
klass = Object.const_get class_name
|
16
|
+
item = klass.read(tmp)
|
17
|
+
items << item
|
18
|
+
tmp = tmp[item.len..-1]
|
19
|
+
end
|
20
|
+
items
|
21
|
+
end
|
22
|
+
|
23
|
+
def set(value)
|
24
|
+
self.binary = value.map(&:to_binary_s).join
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def name
|
30
|
+
plural = self.class.to_s
|
31
|
+
return plural[0..-4] + 'y' if plural[-3..-1] == 'ies'
|
32
|
+
plural[0..-2]
|
33
|
+
end
|
34
|
+
|
35
|
+
def types
|
36
|
+
Object.const_get(name + '::TYPES')
|
37
|
+
end
|
38
|
+
end
|
@@ -31,8 +31,8 @@ class OFFeaturesReply < OFMessage
|
|
31
31
|
:enqueue
|
32
32
|
]
|
33
33
|
array :ports,
|
34
|
-
|
35
|
-
|
34
|
+
type: :of_physical_port,
|
35
|
+
initial_length: -> { (len - ports.rel_offset) / 48 }
|
36
36
|
|
37
37
|
def body_length
|
38
38
|
24 + ports.to_binary_s.length
|
data/lib/messages/message.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
(Dir[File.expand_path '../helpers/**/*.rb', __dir__] +
|
2
2
|
Dir[File.expand_path '../structs/**/*.rb', __dir__] +
|
3
3
|
Dir[File.expand_path '../actions/**/*.rb', __dir__] +
|
4
|
-
Dir[File.expand_path '
|
4
|
+
Dir[File.expand_path 'statistics/**/*.rb', __dir__]).each do |file|
|
5
5
|
require file
|
6
6
|
end
|
7
7
|
|
data/lib/messages/port_mod.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'message'
|
2
|
+
|
3
|
+
class OFQueueGetConfigReply < OFMessage
|
4
|
+
of_port_number_strict :port
|
5
|
+
uint48 :padding
|
6
|
+
hide :padding
|
7
|
+
array :queues,
|
8
|
+
type: :of_packet_queue,
|
9
|
+
read_until: :eof
|
10
|
+
|
11
|
+
def body_length
|
12
|
+
8 + queues.to_binary_s.length
|
13
|
+
end
|
14
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require_relative 'queue_properties/queue_properties'
|
2
|
+
|
3
|
+
class OFPacketQueue < BinData::Record
|
4
|
+
endian :big
|
5
|
+
uint32 :queue_id, initial_value: 0
|
6
|
+
uint16 :len, value: -> { 8 + properties.to_binary_s.length }
|
7
|
+
uint16 :padding
|
8
|
+
hide :padding
|
9
|
+
of_queue_properties :properties, length: -> { len - 8 }
|
10
|
+
end
|
data/lib/structs/port_number.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
require 'bindata'
|
2
2
|
|
3
|
+
class OFPortNumberStrict < BinData::Primitive
|
4
|
+
endian :big
|
5
|
+
uint16 :port_number, initial_value: 0
|
6
|
+
|
7
|
+
def get
|
8
|
+
port_number
|
9
|
+
end
|
10
|
+
|
11
|
+
def set(value)
|
12
|
+
raise ArgumentError, 'Invalid port number.' unless (0..OFPortNumber::MAX).include? value
|
13
|
+
self.port_number = value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
3
17
|
class OFPortNumber < BinData::Primitive
|
4
18
|
NUMBERS = {
|
5
19
|
in_port: 0xfff8,
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Dir[File.expand_path '../../helpers/**/*.rb', __dir__].each do |file|
|
2
|
+
require file
|
3
|
+
end
|
4
|
+
|
5
|
+
class OFQueueProperty < SuperclassBase
|
6
|
+
HEADER_LENGTH = 8
|
7
|
+
TYPES = [
|
8
|
+
:none,
|
9
|
+
:min_rate
|
10
|
+
]
|
11
|
+
|
12
|
+
enum16 :type, list: TYPES, asserted_value: -> { type_str.to_sym }
|
13
|
+
uint16 :len, value: -> { HEADER_LENGTH + body_length }
|
14
|
+
uint32 :padding
|
15
|
+
hide :padding
|
16
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'queue_property'
|
2
|
+
|
3
|
+
class OFQueuePropertyMinRate < OFQueueProperty
|
4
|
+
class Rate < BinData::Primitive
|
5
|
+
endian :big
|
6
|
+
uint16 :rate, initial_value: 0
|
7
|
+
|
8
|
+
def get
|
9
|
+
return :disabled if rate > 1000
|
10
|
+
rate
|
11
|
+
end
|
12
|
+
|
13
|
+
def set(value)
|
14
|
+
value = 0xffff if value == :disabled
|
15
|
+
self.rate = value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
rate :rate
|
20
|
+
uint48 :padding2
|
21
|
+
hide :padding2
|
22
|
+
|
23
|
+
def body_length
|
24
|
+
8
|
25
|
+
end
|
26
|
+
end
|
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe OFBarrierReply do
|
4
|
+
let(:data) { [1, 19, 0, 8, 0, 0, 0, 1].pack('C*') }
|
5
|
+
|
4
6
|
it 'should read binary' do
|
5
|
-
msg = OFBarrierReply.read
|
7
|
+
msg = OFBarrierReply.read(data)
|
6
8
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
7
9
|
expect(msg.type).to eq(:barrier_reply)
|
8
10
|
expect(msg.len).to eq(8)
|
9
11
|
expect(msg.xid).to eq(1)
|
10
12
|
end
|
13
|
+
it 'should be parsable' do
|
14
|
+
msg = OFParser.read(data)
|
15
|
+
expect(msg.class).to eq(OFBarrierReply)
|
16
|
+
end
|
11
17
|
it 'should initialize with default values' do
|
12
18
|
msg = OFBarrierReply.new
|
13
19
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe OFBarrierRequest do
|
4
|
+
let(:data) { [1, 18, 0, 8, 0, 0, 0, 1].pack('C*') }
|
5
|
+
|
4
6
|
it 'should read binary' do
|
5
|
-
msg = OFBarrierRequest.read
|
7
|
+
msg = OFBarrierRequest.read(data)
|
6
8
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
7
9
|
expect(msg.type).to eq(:barrier_request)
|
8
10
|
expect(msg.len).to eq(8)
|
9
11
|
expect(msg.xid).to eq(1)
|
10
12
|
end
|
13
|
+
it 'should be parsable' do
|
14
|
+
msg = OFParser.read(data)
|
15
|
+
expect(msg.class).to eq(OFBarrierRequest)
|
16
|
+
end
|
11
17
|
it 'should initialize with default values' do
|
12
18
|
msg = OFBarrierRequest.new
|
13
19
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
@@ -1,14 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe OFEchoReply do
|
4
|
+
let(:data) { [1, 3, 0, 8, 0, 0, 0, 1].pack('C*') }
|
5
|
+
|
4
6
|
it 'should read binary' do
|
5
|
-
msg = OFEchoReply.read
|
7
|
+
msg = OFEchoReply.read(data)
|
6
8
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
7
9
|
expect(msg.type).to eq(:echo_reply)
|
8
10
|
expect(msg.len).to eq(8)
|
9
11
|
expect(msg.xid).to eq(1)
|
10
12
|
expect(msg.data).to be_empty
|
11
13
|
end
|
14
|
+
it 'should be parsable' do
|
15
|
+
msg = OFParser.read(data)
|
16
|
+
expect(msg.class).to eq(OFEchoReply)
|
17
|
+
end
|
12
18
|
it 'should read binary with data' do
|
13
19
|
msg = OFEchoReply.read [1, 3, 0, 10, 0, 0, 0, 1, 10, 20].pack('C*')
|
14
20
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
@@ -1,14 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe OFEchoRequest do
|
4
|
+
let(:data) { [1, 2, 0, 8, 0, 0, 0, 1].pack('C*') }
|
5
|
+
|
4
6
|
it 'should read binary' do
|
5
|
-
msg = OFEchoRequest.read
|
7
|
+
msg = OFEchoRequest.read(data)
|
6
8
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
7
9
|
expect(msg.type).to eq(:echo_request)
|
8
10
|
expect(msg.len).to eq(8)
|
9
11
|
expect(msg.xid).to eq(1)
|
10
12
|
expect(msg.data).to be_empty
|
11
13
|
end
|
14
|
+
it 'should be parsable' do
|
15
|
+
msg = OFParser.read(data)
|
16
|
+
expect(msg.class).to eq(OFEchoRequest)
|
17
|
+
end
|
12
18
|
it 'should read binary with data' do
|
13
19
|
msg = OFEchoRequest.read [1, 2, 0, 10, 0, 0, 0, 1, 10, 20].pack('C*')
|
14
20
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
data/spec/messages/error_spec.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe OFError do
|
4
|
-
|
5
|
-
|
4
|
+
let(:data) {
|
5
|
+
[
|
6
6
|
1, 1, 0, 16, 0, 0, 0, 1, # header
|
7
7
|
0, 0, # type
|
8
8
|
0, 0, # code
|
9
9
|
1, 2, 3, 4 # data
|
10
10
|
].pack('C*')
|
11
|
+
}
|
12
|
+
|
13
|
+
it 'should read binary' do
|
14
|
+
msg = OFError.read(data)
|
11
15
|
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
12
16
|
expect(msg.type).to eq(:error)
|
13
17
|
expect(msg.len).to eq(16)
|
@@ -16,6 +20,10 @@ describe OFError do
|
|
16
20
|
expect(msg.error_code).to eq(:incompatible)
|
17
21
|
expect(msg.data).to eq([1, 2, 3, 4].pack('C*'))
|
18
22
|
end
|
23
|
+
it 'should be parsable' do
|
24
|
+
msg = OFParser.read(data)
|
25
|
+
expect(msg.class).to eq(OFError)
|
26
|
+
end
|
19
27
|
it 'should read binary' do
|
20
28
|
msg = OFError.read [
|
21
29
|
1, 1, 0, 12, 0, 0, 0, 1, # header
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe OFFeaturesReply do
|
4
|
-
|
5
|
-
|
4
|
+
let(:data) {
|
5
|
+
[
|
6
6
|
1, 6, 0, 128, 0, 0, 0, 1, # header
|
7
7
|
0, 0, 0, 0, 0, 0, 0, 42, # datapath_id
|
8
8
|
0, 0, 0, 10, # n_buffers
|
@@ -37,43 +37,9 @@ describe OFFeaturesReply do
|
|
37
37
|
0, 0, 0x0f, 0xff, # supported_features
|
38
38
|
0, 0, 0x0f, 0xff # peer_features
|
39
39
|
].pack('C*')
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
expect(msg.xid).to eq(1)
|
44
|
-
expect(msg.datapath_id).to eq(42)
|
45
|
-
expect(msg.n_buffers).to eq(10)
|
46
|
-
expect(msg.n_tables).to eq(5)
|
47
|
-
expect(msg.capabilities).to eq([
|
48
|
-
:flow_stats,
|
49
|
-
:table_stats,
|
50
|
-
:port_stats,
|
51
|
-
:stp,
|
52
|
-
:reserved,
|
53
|
-
:ip_reasm,
|
54
|
-
:queue_stats,
|
55
|
-
:arp_match_ip
|
56
|
-
])
|
57
|
-
expect(msg.actions).to eq([
|
58
|
-
:output,
|
59
|
-
:set_vlan_vid,
|
60
|
-
:set_vlan_pcp,
|
61
|
-
:strip_vlan,
|
62
|
-
:set_dl_src,
|
63
|
-
:set_dl_dst,
|
64
|
-
:set_nw_src,
|
65
|
-
:set_nw_dst,
|
66
|
-
:set_nw_tos,
|
67
|
-
:set_tp_src,
|
68
|
-
:set_tp_dst,
|
69
|
-
:enqueue
|
70
|
-
])
|
71
|
-
expect(msg.ports.length).to eq(2)
|
72
|
-
expect(msg.ports[0].port_number).to eq(1)
|
73
|
-
expect(msg.ports[1].port_number).to eq(2)
|
74
|
-
end
|
75
|
-
it 'should read a real binary message' do
|
76
|
-
msg = OFFeaturesReply.read [
|
40
|
+
}
|
41
|
+
let(:real_data) {
|
42
|
+
[
|
77
43
|
1, 6, 0, 176, 0, 0, 0, 0,
|
78
44
|
0, 0, 0, 0, 0, 0, 0, 1,
|
79
45
|
0, 0, 1, 0,
|
@@ -121,6 +87,51 @@ describe OFFeaturesReply do
|
|
121
87
|
0, 0, 0, 0,
|
122
88
|
0, 0, 0, 0
|
123
89
|
].pack('C*')
|
90
|
+
}
|
91
|
+
|
92
|
+
it 'should read binary' do
|
93
|
+
msg = OFFeaturesReply.read(data)
|
94
|
+
expect(msg.version).to eq(OFMessage::OFP_VERSION)
|
95
|
+
expect(msg.type).to eq(:features_reply)
|
96
|
+
expect(msg.len).to eq(128)
|
97
|
+
expect(msg.xid).to eq(1)
|
98
|
+
expect(msg.datapath_id).to eq(42)
|
99
|
+
expect(msg.n_buffers).to eq(10)
|
100
|
+
expect(msg.n_tables).to eq(5)
|
101
|
+
expect(msg.capabilities).to eq([
|
102
|
+
:flow_stats,
|
103
|
+
:table_stats,
|
104
|
+
:port_stats,
|
105
|
+
:stp,
|
106
|
+
:reserved,
|
107
|
+
:ip_reasm,
|
108
|
+
:queue_stats,
|
109
|
+
:arp_match_ip
|
110
|
+
])
|
111
|
+
expect(msg.actions).to eq([
|
112
|
+
:output,
|
113
|
+
:set_vlan_vid,
|
114
|
+
:set_vlan_pcp,
|
115
|
+
:strip_vlan,
|
116
|
+
:set_dl_src,
|
117
|
+
:set_dl_dst,
|
118
|
+
:set_nw_src,
|
119
|
+
:set_nw_dst,
|
120
|
+
:set_nw_tos,
|
121
|
+
:set_tp_src,
|
122
|
+
:set_tp_dst,
|
123
|
+
:enqueue
|
124
|
+
])
|
125
|
+
expect(msg.ports.length).to eq(2)
|
126
|
+
expect(msg.ports[0].port_number).to eq(1)
|
127
|
+
expect(msg.ports[1].port_number).to eq(2)
|
128
|
+
end
|
129
|
+
it 'should be parsable' do
|
130
|
+
msg = OFParser.read(data)
|
131
|
+
expect(msg.class).to eq(OFFeaturesReply)
|
132
|
+
end
|
133
|
+
it 'should read a real binary message' do
|
134
|
+
msg = OFFeaturesReply.read(real_data)
|
124
135
|
expect(msg.ports.length).to eq(3)
|
125
136
|
end
|
126
137
|
it 'should initialize with default values' do
|