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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/lib/actions/actions.rb +1 -24
  3. data/lib/helpers/array_of_subclasses.rb +38 -0
  4. data/lib/helpers/superclass_base.rb +2 -0
  5. data/lib/messages/features_reply.rb +2 -2
  6. data/lib/messages/message.rb +1 -1
  7. data/lib/messages/port_mod.rb +2 -0
  8. data/lib/messages/queue_get_config_reply.rb +14 -0
  9. data/lib/messages/queue_get_config_request.rb +11 -0
  10. data/lib/{statistics → messages/statistics}/aggregate_statistics_reply.rb +0 -0
  11. data/lib/{statistics → messages/statistics}/aggregate_statistics_request.rb +0 -0
  12. data/lib/{statistics → messages/statistics}/description_statistics.rb +0 -0
  13. data/lib/{statistics → messages/statistics}/flow_statistics_reply.rb +0 -0
  14. data/lib/{statistics → messages/statistics}/flow_statistics_request.rb +0 -0
  15. data/lib/{statistics → messages/statistics}/port_statistics_reply.rb +1 -1
  16. data/lib/{statistics → messages/statistics}/port_statistics_request.rb +1 -1
  17. data/lib/{statistics → messages/statistics}/queue_statistics_reply.rb +1 -1
  18. data/lib/{statistics → messages/statistics}/queue_statistics_request.rb +1 -1
  19. data/lib/{statistics → messages/statistics}/table_statistics.rb +1 -1
  20. data/lib/{statistics → messages/statistics}/vendor_statistics.rb +0 -0
  21. data/lib/openflow-protocol/version.rb +1 -1
  22. data/lib/structs/packet_queue.rb +10 -0
  23. data/lib/structs/port_number.rb +14 -0
  24. data/lib/structs/queue_properties/queue_properties.rb +5 -0
  25. data/lib/structs/queue_properties/queue_property.rb +16 -0
  26. data/lib/structs/queue_properties/queue_property_min_rate.rb +26 -0
  27. data/lib/structs/queue_properties/queue_property_none.rb +3 -0
  28. data/spec/actions/actions_spec.rb +1 -1
  29. data/spec/messages/barrier_reply_spec.rb +7 -1
  30. data/spec/messages/barrier_request_spec.rb +7 -1
  31. data/spec/messages/echo_reply_spec.rb +7 -1
  32. data/spec/messages/echo_request_spec.rb +7 -1
  33. data/spec/messages/error_spec.rb +10 -2
  34. data/spec/messages/features_reply_spec.rb +50 -39
  35. data/spec/messages/features_request_spec.rb +7 -1
  36. data/spec/messages/flow_mod_spec.rb +10 -2
  37. data/spec/messages/flow_removed_spec.rb +10 -2
  38. data/spec/messages/get_config_reply_spec.rb +10 -2
  39. data/spec/messages/get_config_request_spec.rb +7 -1
  40. data/spec/messages/hello_spec.rb +7 -1
  41. data/spec/messages/packet_in_spec.rb +10 -2
  42. data/spec/messages/packet_out_spec.rb +10 -2
  43. data/spec/messages/port_mod_spec.rb +10 -2
  44. data/spec/messages/port_status_spec.rb +10 -2
  45. data/spec/messages/queue_get_config_reply_spec.rb +68 -0
  46. data/spec/messages/queue_get_config_request_spec.rb +40 -0
  47. data/spec/messages/set_config_spec.rb +10 -2
  48. data/spec/{statistics → messages/statistics}/aggregate_statistics_reply_spec.rb +0 -0
  49. data/spec/{statistics → messages/statistics}/aggregate_statistics_request_spec.rb +0 -0
  50. data/spec/{statistics → messages/statistics}/description_statistics_spec.rb +0 -0
  51. data/spec/{statistics → messages/statistics}/flow_statistics_reply_spec.rb +0 -0
  52. data/spec/{statistics → messages/statistics}/flow_statistics_request_spec.rb +0 -0
  53. data/spec/{statistics → messages/statistics}/port_statistics_reply_spec.rb +0 -0
  54. data/spec/{statistics → messages/statistics}/port_statistics_request_spec.rb +0 -0
  55. data/spec/{statistics → messages/statistics}/queue_statistics_reply_spec.rb +0 -0
  56. data/spec/{statistics → messages/statistics}/queue_statistics_request_spec.rb +0 -0
  57. data/spec/{statistics → messages/statistics}/table_statistics_spec.rb +0 -0
  58. data/spec/{statistics → messages/statistics}/vendor_statistics_spec.rb +0 -0
  59. data/spec/messages/statistics_reply_spec.rb +77 -20
  60. data/spec/messages/statistics_request_spec.rb +13 -5
  61. data/spec/messages/vendor_spec.rb +10 -2
  62. data/spec/structs/packet_queue_spec.rb +37 -0
  63. data/spec/structs/port_number_spec.rb +19 -0
  64. data/spec/structs/queue_properties/queue_properties_spec.rb +29 -0
  65. data/spec/structs/queue_properties/queue_property_min_rate_spec.rb +32 -0
  66. data/spec/structs/queue_properties/queue_property_none_spec.rb +14 -0
  67. metadata +55 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0efcfc19372c5ff81c76eef6c74912c9ddfccaf
4
- data.tar.gz: 02a45e643b2ea6c53f877dfac8cffcdc680c1711
3
+ metadata.gz: b787a021c7be6ba96d78b7f71f9d93676c709bd7
4
+ data.tar.gz: 80ea8bef3b0e8fbd6783d8fdb35fb278032c9d0e
5
5
  SHA512:
6
- metadata.gz: 77b3a36050c5e976899c07f2a9a8ff4917f8b8e4c5cbce3070ea02b262990f9ba67b2324095edba3b83e160fdcb4bfa7c0c6d171abc0d8cff852f4accbacc1cb
7
- data.tar.gz: de3deb39ea4a6e6ca09c0fd3a5eeca3769ab1c62d97945990cca0131f6c9db2c0f27eca5f98da8678f2f78bc4f75a1331077a259c50c6f53a09719f33f89168d
6
+ metadata.gz: 842cbdc2c9b75e80d1dbb53d853fa6c578bbc8ec05d3db6bb8450fd7be2017fb8586c1ba435410b717979e6fe95171fb8d776677c9b9a8c4a59e65e4f79ec0dc
7
+ data.tar.gz: b1139123757191b1c60e00866e8543c423e324f70f49ea23e4ee8ee02fbc2ed72b13c1ae891255e6487e4c9c8cf8137028235956fed6baaf3f8dd76a5c44e47d
@@ -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 < BinData::Primitive
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
@@ -10,6 +10,8 @@ class SuperclassBase < BinData::Record
10
10
  super
11
11
  if self.class.name[2..7] == 'Action'
12
12
  name = self.class.name[8..-1]
13
+ elsif self.class.name[2..14] == 'QueueProperty'
14
+ name = self.class.name[15..-1]
13
15
  else
14
16
  name = self.class.name[2..-1]
15
17
  end
@@ -31,8 +31,8 @@ class OFFeaturesReply < OFMessage
31
31
  :enqueue
32
32
  ]
33
33
  array :ports,
34
- type: :of_physical_port,
35
- initial_length: -> { (len - ports.rel_offset) / 48 }
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
@@ -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 '../statistics/**/*.rb', __dir__]).each do |file|
4
+ Dir[File.expand_path 'statistics/**/*.rb', __dir__]).each do |file|
5
5
  require file
6
6
  end
7
7
 
@@ -6,6 +6,8 @@ class OFPortMod < OFMessage
6
6
  flags32 :config, list: OFPhysicalPort::CONFIG
7
7
  flags32 :mask, list: OFPhysicalPort::CONFIG
8
8
  flags32 :advertise, list: OFPhysicalPort::FEATURES
9
+ uint32 :padding
10
+ hide :padding
9
11
 
10
12
  def body_length
11
13
  24
@@ -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
@@ -0,0 +1,11 @@
1
+ require_relative 'message'
2
+
3
+ class OFQueueGetConfigRequest < OFMessage
4
+ of_port_number_strict :port
5
+ uint16 :padding
6
+ hide :padding
7
+
8
+ def body_length
9
+ 4
10
+ end
11
+ end
@@ -1,4 +1,4 @@
1
- require_relative '../structs/port_number'
1
+ require_relative '../../structs/port_number'
2
2
 
3
3
  class OFPortStatisticsReply < BinData::Record
4
4
  endian :big
@@ -1,4 +1,4 @@
1
- require_relative '../structs/port_number'
1
+ require_relative '../../structs/port_number'
2
2
 
3
3
  class OFPortStatisticsRequest < BinData::Record
4
4
  endian :big
@@ -1,4 +1,4 @@
1
- require_relative '../structs/port_number'
1
+ require_relative '../../structs/port_number'
2
2
 
3
3
  class OFQueueStatisticsReply < BinData::Record
4
4
  endian :big
@@ -1,4 +1,4 @@
1
- require_relative '../structs/port_number'
1
+ require_relative '../../structs/port_number'
2
2
 
3
3
  class OFQueueStatisticsRequest < BinData::Record
4
4
  endian :big
@@ -1,4 +1,4 @@
1
- require_relative '../structs/match'
1
+ require_relative '../../structs/match'
2
2
 
3
3
  class OFTableStatistics < BinData::Record
4
4
  TABLE_IDS = {emergency: 0xfe, all: 0xff}
@@ -1,5 +1,5 @@
1
1
  module OpenFlow
2
2
  module Protocol
3
- VERSION = '0.1.6'
3
+ VERSION = '0.1.7'
4
4
  end
5
5
  end
@@ -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
@@ -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,5 @@
1
+ Dir[File.expand_path 'queue_property_*.rb', __dir__].each do |file|
2
+ require file
3
+ end
4
+
5
+ class OFQueueProperties < ArrayOfSubclasses; end
@@ -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
@@ -0,0 +1,3 @@
1
+ require_relative 'queue_property'
2
+
3
+ class OFQueuePropertyNone < OFQueueProperty; end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe OFActionOutput do
3
+ describe OFActions do
4
4
  it 'should read binary' do
5
5
  actions = OFActions.read [
6
6
  # output
@@ -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 [1, 19, 0, 8, 0, 0, 0, 1].pack('C*')
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 [1, 18, 0, 8, 0, 0, 0, 1].pack('C*')
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 [1, 3, 0, 8, 0, 0, 0, 1].pack('C*')
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 [1, 2, 0, 8, 0, 0, 0, 1].pack('C*')
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)
@@ -1,13 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe OFError do
4
- it 'should read binary' do
5
- msg = OFError.read [
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
- it 'should read binary' do
5
- msg = OFFeaturesReply.read [
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
- expect(msg.version).to eq(OFMessage::OFP_VERSION)
41
- expect(msg.type).to eq(:features_reply)
42
- expect(msg.len).to eq(128)
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