pio 0.23.1 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/README.md +2 -0
  4. data/Rakefile +1 -1
  5. data/features/open_flow10/barrier_reply.feature +58 -0
  6. data/features/open_flow10/barrier_request.feature +58 -0
  7. data/features/open_flow10/echo_reply.feature +50 -40
  8. data/features/open_flow10/echo_request.feature +54 -51
  9. data/features/open_flow10/features_reply.feature +62 -63
  10. data/features/open_flow10/features_request.feature +2 -19
  11. data/features/open_flow10/flow_mod.feature +1 -0
  12. data/features/open_flow10/hello.feature +38 -44
  13. data/features/open_flow10/packet_in.feature +1 -2
  14. data/features/open_flow10/packet_in.raw +0 -0
  15. data/features/open_flow10/packet_out.feature +14 -14
  16. data/features/open_flow10/port_status.feature +17 -17
  17. data/features/open_flow13/apply_actions.feature +15 -17
  18. data/features/open_flow13/echo_reply.feature +58 -58
  19. data/features/open_flow13/echo_request.feature +58 -58
  20. data/features/open_flow13/features_reply.feature +2 -6
  21. data/features/open_flow13/features_request.feature +3 -23
  22. data/features/open_flow13/flow_mod.feature +86 -93
  23. data/features/open_flow13/goto_table.feature +4 -4
  24. data/features/open_flow13/hello.feature +8 -15
  25. data/features/open_flow13/match.feature +14 -3
  26. data/features/open_flow13/meter.feature +3 -3
  27. data/features/open_flow13/oxm_experimenter_stratos_basic_dot11.raw +0 -0
  28. data/features/open_flow13/oxm_invalid_field.raw +0 -0
  29. data/features/open_flow13/packet_in.feature +15 -20
  30. data/features/open_flow13/packet_out.feature +39 -42
  31. data/features/open_flow13/send_out_port.feature +1 -5
  32. data/features/open_flow13/write_metadata.feature +3 -3
  33. data/features/open_flow_read.feature +43 -0
  34. data/features/open_flow_version.feature +10 -0
  35. data/features/step_definitions/open_flow_steps.rb +10 -2
  36. data/features/step_definitions/packet_data_steps.rb +4 -0
  37. data/features/support/hooks.rb +7 -0
  38. data/lib/pio.rb +1 -1
  39. data/lib/pio/monkey_patch/integer/ranges.rb +4 -0
  40. data/lib/pio/open_flow.rb +54 -16
  41. data/lib/pio/open_flow/datapath_id.rb +26 -0
  42. data/lib/pio/open_flow/echo.rb +44 -0
  43. data/lib/pio/open_flow/format.rb +45 -0
  44. data/lib/pio/open_flow/message.rb +88 -0
  45. data/lib/pio/open_flow/open_flow_header.rb +0 -14
  46. data/lib/pio/open_flow10.rb +3 -8
  47. data/lib/pio/open_flow10/actions.rb +1 -1
  48. data/lib/pio/open_flow10/barrier_reply.rb +21 -0
  49. data/lib/pio/open_flow10/barrier_request.rb +22 -0
  50. data/lib/pio/open_flow10/echo.rb +15 -11
  51. data/lib/pio/open_flow10/features.rb +99 -71
  52. data/lib/pio/open_flow10/flow_mod.rb +73 -66
  53. data/lib/pio/open_flow10/hello.rb +19 -4
  54. data/lib/pio/open_flow10/match.rb +133 -131
  55. data/lib/pio/open_flow10/packet_in.rb +55 -49
  56. data/lib/pio/open_flow10/packet_out.rb +31 -24
  57. data/lib/pio/open_flow10/port_status.rb +54 -27
  58. data/lib/pio/open_flow10/send_out_port.rb +66 -64
  59. data/lib/pio/open_flow13.rb +0 -15
  60. data/lib/pio/open_flow13/echo.rb +11 -68
  61. data/lib/pio/open_flow13/features_reply.rb +48 -77
  62. data/lib/pio/open_flow13/features_request.rb +16 -45
  63. data/lib/pio/open_flow13/flow_mod.rb +125 -148
  64. data/lib/pio/open_flow13/goto_table.rb +1 -0
  65. data/lib/pio/open_flow13/hello.rb +54 -84
  66. data/lib/pio/open_flow13/match.rb +69 -11
  67. data/lib/pio/open_flow13/meter.rb +1 -0
  68. data/lib/pio/open_flow13/packet_in.rb +38 -50
  69. data/lib/pio/open_flow13/packet_out.rb +50 -75
  70. data/lib/pio/open_flow13/send_out_port.rb +34 -34
  71. data/lib/pio/open_flow13/write_metadata.rb +1 -0
  72. data/lib/pio/parser.rb +3 -0
  73. data/lib/pio/version.rb +1 -1
  74. data/pio.gemspec +6 -6
  75. data/spec/pio/open_flow10/echo_reply_spec.rb +7 -0
  76. data/spec/pio/open_flow10/echo_request_spec.rb +7 -0
  77. data/spec/pio/open_flow10/features_reply_spec.rb +8 -0
  78. data/spec/pio/open_flow10/features_request_spec.rb +13 -0
  79. data/spec/pio/open_flow10/flow_mod_spec.rb +17 -16
  80. data/spec/pio/open_flow10/hello_spec.rb +7 -0
  81. data/spec/pio/open_flow10/match_spec.rb +8 -6
  82. data/spec/pio/open_flow10/packet_in_spec.rb +14 -0
  83. data/spec/pio/open_flow10/packet_out_spec.rb +21 -14
  84. data/spec/pio/open_flow10/send_out_port_spec.rb +4 -4
  85. data/spec/pio/open_flow10/wildcards_spec.rb +2 -2
  86. data/spec/pio/open_flow13/echo_reply_spec.rb +7 -0
  87. data/spec/pio/open_flow13/echo_request_spec.rb +7 -0
  88. data/spec/pio/open_flow13/features_reply_spec.rb +8 -0
  89. data/spec/pio/open_flow13/features_request_spec.rb +13 -0
  90. data/spec/pio/open_flow13/hello_spec.rb +14 -59
  91. data/spec/pio/open_flow13/packet_in_spec.rb +14 -0
  92. data/spec/pio/open_flow13/packet_out_spec.rb +7 -0
  93. data/spec/pio/open_flow_spec.rb +34 -0
  94. data/spec/spec_helper.rb +1 -0
  95. data/spec/support/shared_examples_for_openflow_messages.rb +75 -0
  96. metadata +215 -170
  97. data/bin/byebug +0 -16
  98. data/bin/terminal-notifier +0 -16
  99. data/lib/pio/open_flow10/message.rb +0 -78
  100. data/spec/pio/open_flow/type_spec.rb +0 -5
data/lib/pio.rb CHANGED
@@ -5,5 +5,5 @@ require 'pio/dhcp'
5
5
  require 'pio/icmp'
6
6
  require 'pio/lldp'
7
7
  require 'pio/mac'
8
- require 'pio/open_flow10'
8
+ require 'pio/open_flow'
9
9
  require 'pio/udp'
@@ -14,6 +14,10 @@ module MonkeyPatch
14
14
  _within_range? 32
15
15
  end
16
16
 
17
+ def unsigned_64bit?
18
+ _within_range? 64
19
+ end
20
+
17
21
  def _within_range?(nbit)
18
22
  (0 <= self) && (self < 2**nbit)
19
23
  end
@@ -1,20 +1,58 @@
1
- module Pio
2
- # OpenFlow specific types.
3
- module OpenFlow
4
- # OFPT_* constants.
5
- HELLO = 0
6
- ECHO_REQUEST = 2
7
- ECHO_REPLY = 3
8
- FEATURES_REQUEST = 5
9
- FEATURES_REPLY = 6
10
- PACKET_IN = 10
11
- PORT_STATUS = 12
12
- PACKET_OUT = 13
13
- FLOW_MOD = 14
14
- end
15
- end
16
-
1
+ require 'pio/open_flow/datapath_id'
17
2
  require 'pio/open_flow/flags'
3
+ require 'pio/open_flow/format'
4
+ require 'pio/open_flow/message'
18
5
  require 'pio/open_flow/open_flow_header'
19
6
  require 'pio/open_flow/phy_port'
20
7
  require 'pio/open_flow/port_number'
8
+ require 'pio/open_flow10'
9
+ require 'pio/open_flow13'
10
+
11
+ module Pio
12
+ # Common OpenFlow modules/classes.
13
+ module OpenFlow
14
+ def self.version
15
+ fail unless @version
16
+ @version
17
+ end
18
+
19
+ def self.switch_version(version)
20
+ [:Barrier, :Echo, :Features, :FlowMod, :Hello, :Match,
21
+ :PacketIn, :PacketOut, :SendOutPort, :PortStatus].each do |each|
22
+ set_message_class_name each, version
23
+ @version = version.to_s
24
+ end
25
+ end
26
+
27
+ # rubocop:disable MethodLength
28
+ def self.read(binary)
29
+ parser = {
30
+ 0 => Pio::Hello,
31
+ 2 => Pio::Echo::Request,
32
+ 3 => Pio::Echo::Reply,
33
+ 5 => Pio::Features::Request,
34
+ 6 => Pio::Features::Reply,
35
+ 10 => Pio::PacketIn,
36
+ 12 => Pio::PortStatus
37
+ }
38
+ header = OpenFlowHeaderParser.read(binary)
39
+ parser.fetch(header.message_type).read(binary)
40
+ rescue
41
+ raise "Unknown message type #{header.message_type}"
42
+ end
43
+ # rubocop:enable MethodLength
44
+
45
+ def self.set_message_class_name(klass_name, version)
46
+ open_flow_module = Pio.const_get(version)
47
+ return unless open_flow_module.const_defined?(klass_name)
48
+ Pio.__send__ :remove_const, klass_name if Pio.const_defined?(klass_name)
49
+ Pio.const_set(klass_name, open_flow_module.const_get(klass_name))
50
+ rescue NameError
51
+ raise "#{version} is not supported yet."
52
+ end
53
+ private_class_method :set_message_class_name
54
+
55
+ # The default OpenFlow version is 1.0
56
+ switch_version 'OpenFlow10'
57
+ end
58
+ end
@@ -0,0 +1,26 @@
1
+ require 'bindata'
2
+ require 'pio/monkey_patch/integer'
3
+
4
+ module Pio
5
+ module OpenFlow
6
+ # Datapath unique ID. The lower 48-bits are for a MAC address,
7
+ # while the upper 16-bits are implementer-defined.
8
+ class DatapathId < BinData::Primitive
9
+ endian :big
10
+
11
+ uint64 :datapath_id
12
+
13
+ def set(value)
14
+ unless value.unsigned_64bit?
15
+ fail(ArgumentError,
16
+ 'Datapath ID should be an unsigned 64-bit integer.')
17
+ end
18
+ self.datapath_id = value
19
+ end
20
+
21
+ def get
22
+ datapath_id
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ require 'pio/open_flow/format'
2
+ require 'pio/open_flow/message'
3
+
4
+ module Pio
5
+ module OpenFlow
6
+ # Base class of Echo Request and Reply.
7
+ class Echo < OpenFlow::Message
8
+ # rubocop:disable MethodLength
9
+ def self.inherited(child)
10
+ child.module_eval <<-EOS
11
+ class Format < BinData::Record
12
+ extend OpenFlow::Format
13
+
14
+ header version: :of_version,
15
+ message_type: :of_message_type
16
+ string :body, read_length: -> { message_length - header_length }
17
+
18
+ def user_data
19
+ body
20
+ end
21
+ end
22
+ EOS
23
+ end
24
+ # rubocop:enable MethodLength
25
+
26
+ def self.version(version)
27
+ const_get(:Format).tap do |klass|
28
+ klass.__send__(:define_method, :of_version) { version }
29
+ klass.class_eval { private :of_version }
30
+ end
31
+ end
32
+
33
+ def self.message_type(message_type)
34
+ const_get(:Format).tap do |klass|
35
+ klass.__send__(:define_method, :of_message_type) { message_type }
36
+ klass.class_eval { private :of_message_type }
37
+ end
38
+ end
39
+
40
+ body_option :body
41
+ body_option :user_data
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,45 @@
1
+ require 'pio/open_flow/open_flow_header'
2
+
3
+ module Pio
4
+ module OpenFlow
5
+ # OpenFlow message definition macros.
6
+ module Format
7
+ include Forwardable
8
+
9
+ # rubocop:disable NestedMethodDefinition
10
+ def self.extended(base)
11
+ base.module_eval do
12
+ def header_length
13
+ 8
14
+ end
15
+
16
+ def method_missing(method, *args, &block)
17
+ body.__send__ method, *args, &block
18
+ end
19
+ end
20
+ end
21
+ # rubocop:enable NestedMethodDefinition
22
+
23
+ # rubocop:disable MethodLength
24
+ def header(options)
25
+ module_eval do
26
+ endian :big
27
+
28
+ open_flow_header :header,
29
+ ofp_version_value: options.fetch(:version),
30
+ message_type_value: options.fetch(:message_type)
31
+
32
+ def_delegators :header, :snapshot
33
+ def_delegators :snapshot, :ofp_version
34
+ def_delegators :snapshot, :message_type
35
+ def_delegators :snapshot, :message_length
36
+ def_delegators :snapshot, :transaction_id
37
+ def_delegator :snapshot, :transaction_id, :xid
38
+
39
+ alias_method :to_binary, :to_binary_s
40
+ end
41
+ end
42
+ # rubocop:enable MethodLength
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,88 @@
1
+ module Pio
2
+ module OpenFlow
3
+ # OpenFlow messages.
4
+ class Message
5
+ # rubocop:disable MethodLength
6
+ def self.inherited(child)
7
+ child.class_eval <<-EOS
8
+ def self.read(raw_data)
9
+ allocate.tap do |message|
10
+ format_klass = self.const_get(:Format)
11
+ message.instance_variable_set(:@format,
12
+ format_klass.read(raw_data))
13
+ end
14
+ rescue BinData::ValidityError
15
+ message_name = name.split('::')[1..-1].join(' ')
16
+ raise Pio::ParseError, "Invalid \#{message_name} message."
17
+ end
18
+ EOS
19
+ end
20
+ # rubocop:enable MethodLength
21
+
22
+ def self.body_option(name)
23
+ unless class_variable_defined?(:@@valid_body_options)
24
+ class_variable_set(:@@valid_body_options, [])
25
+ end
26
+ class_variable_set(:@@valid_body_options,
27
+ class_variable_get(:@@valid_body_options) + [name])
28
+ end
29
+
30
+ def initialize(user_options = {})
31
+ validate_user_options user_options
32
+ @format = self.class.const_get(:Format).new(parse_options(user_options))
33
+ end
34
+
35
+ def method_missing(method, *args, &block)
36
+ @format.__send__ method, *args, &block
37
+ end
38
+
39
+ private
40
+
41
+ def validate_user_options(user_options)
42
+ unknown_options =
43
+ user_options.keys - valid_header_options - valid_body_options
44
+ return if unknown_options.empty?
45
+ fail "Unknown option: #{unknown_options.first}"
46
+ end
47
+
48
+ def parse_options(user_options)
49
+ if valid_body_options.empty?
50
+ { header: parse_header_options(user_options) }
51
+ else
52
+ { header: parse_header_options(user_options),
53
+ body: parse_body_options(user_options) }
54
+ end
55
+ end
56
+
57
+ def parse_header_options(user_options)
58
+ transaction_id =
59
+ user_options[:transaction_id] || user_options[:xid] || 0
60
+ { transaction_id: transaction_id }
61
+ end
62
+
63
+ def parse_body_options(user_options)
64
+ if valid_body_options.include?(:body)
65
+ return user_options[:body] || user_options[:user_data] || ''
66
+ end
67
+ options = user_options.dup
68
+ options.delete :transaction_id
69
+ options.delete :xid
70
+ dpid = options[:dpid]
71
+ options[:datapath_id] = dpid if dpid
72
+ options.empty? ? {} : options
73
+ end
74
+
75
+ def valid_header_options
76
+ [:transaction_id, :xid]
77
+ end
78
+
79
+ def valid_body_options
80
+ if self.class.class_variable_defined?(:@@valid_body_options)
81
+ self.class.class_variable_get(:@@valid_body_options)
82
+ else
83
+ []
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -22,19 +22,5 @@ module Pio
22
22
  virtual assert: -> { message_type == message_type_value }
23
23
  uint16 :message_length, initial_value: -> { 8 + body.length }
24
24
  transaction_id :transaction_id, initial_value: 0
25
-
26
- # parse header options
27
- class Options
28
- def self.parse(options)
29
- xid = if options.respond_to?(:to_i)
30
- options.to_i
31
- elsif options.respond_to?(:fetch)
32
- options[:transaction_id] || options[:xid] || 0
33
- else
34
- fail TypeError
35
- end
36
- { transaction_id: xid }
37
- end
38
- end
39
25
  end
40
26
  end
@@ -1,11 +1,5 @@
1
- module Pio
2
- # OpenFlow specific types.
3
- module OpenFlow
4
- VERSION = 1
5
- end
6
- end
7
-
8
- require 'pio/open_flow10/actions'
1
+ require 'pio/open_flow10/barrier_reply'
2
+ require 'pio/open_flow10/barrier_request'
9
3
  require 'pio/open_flow10/echo'
10
4
  require 'pio/open_flow10/exact_match'
11
5
  require 'pio/open_flow10/features'
@@ -14,3 +8,4 @@ require 'pio/open_flow10/hello'
14
8
  require 'pio/open_flow10/packet_in'
15
9
  require 'pio/open_flow10/packet_out'
16
10
  require 'pio/open_flow10/port_status'
11
+ require 'pio/open_flow10/send_out_port'
@@ -14,7 +14,7 @@ module Pio
14
14
  # Actions list.
15
15
  class Actions < BinData::Primitive
16
16
  ACTION_CLASS = {
17
- 0 => Pio::SendOutPort,
17
+ 0 => Pio::OpenFlow10::SendOutPort,
18
18
  1 => Pio::SetVlanVid,
19
19
  2 => Pio::SetVlanPriority,
20
20
  3 => Pio::StripVlanHeader,
@@ -0,0 +1,21 @@
1
+ require 'pio/open_flow/format'
2
+ require 'pio/open_flow/message'
3
+
4
+ module Pio
5
+ # OpenFlow 1.0 messages
6
+ module OpenFlow10
7
+ # OpenFlow 1.0 Barrier messages
8
+ module Barrier
9
+ # OpenFlow 1.0 Barrier Request message
10
+ class Reply < OpenFlow::Message
11
+ # OpenFlow 1.0 Barrier Request message format
12
+ class Format < BinData::Record
13
+ extend OpenFlow::Format
14
+
15
+ header version: 1, message_type: 19
16
+ string :body, value: ''
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ require 'pio/open_flow/format'
2
+ require 'pio/open_flow/message'
3
+
4
+ # Base module.
5
+ module Pio
6
+ # OpenFlow 1.0 messages
7
+ module OpenFlow10
8
+ # OpenFlow 1.0 Barrier messages
9
+ module Barrier
10
+ # OpenFlow 1.0 Barrier Request message
11
+ class Request < OpenFlow::Message
12
+ # OpenFlow 1.0 Barrier Request message format
13
+ class Format < BinData::Record
14
+ extend OpenFlow::Format
15
+
16
+ header version: 1, message_type: 18
17
+ string :body, value: ''
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,16 +1,20 @@
1
- require 'forwardable'
2
- require 'pio/open_flow'
3
- require 'pio/open_flow10/message'
1
+ require 'pio/open_flow/echo'
4
2
 
5
3
  module Pio
6
- # OpenFlow 1.0 Echo Request and Reply message.
7
- module Echo
8
- # OpenFlow 1.0 Echo Request message.
9
- class Request; end
10
- OpenFlow::Message.factory(Request, OpenFlow::ECHO_REQUEST)
4
+ module OpenFlow10
5
+ # OpenFlow 1.0 Echo Request and Reply message.
6
+ module Echo
7
+ # OpenFlow 1.0 Echo Request message.
8
+ class Request < OpenFlow::Echo
9
+ version 1
10
+ message_type 2
11
+ end
11
12
 
12
- # OpenFlow 1.0 Echo Reply message.
13
- class Reply; end
14
- OpenFlow::Message.factory(Reply, OpenFlow::ECHO_REPLY)
13
+ # OpenFlow 1.0 Echo Reply message.
14
+ class Reply < OpenFlow::Echo
15
+ version 1
16
+ message_type 3
17
+ end
18
+ end
15
19
  end
16
20
  end
@@ -1,85 +1,113 @@
1
- require 'forwardable'
2
1
  require 'pio/open_flow'
3
2
 
4
3
  module Pio
5
- # OpenFlow 1.0 Features Request and Reply message.
6
- class Features
7
- # OpenFlow 1.0 Features Request message.
8
- class Request; end
9
- OpenFlow::Message.factory(Request, OpenFlow::FEATURES_REQUEST)
10
-
11
- # OpenFlow 1.0 Features Reply message.
12
- class Reply
13
- # Message body of features reply.
14
- class Body < BinData::Record
15
- extend OpenFlow::Flags
16
-
17
- # enum ofp_capabilities
18
- flags_32bit :capabilities,
19
- [:flow_stats,
20
- :table_stats,
21
- :port_stats,
22
- :stp,
23
- :reserved,
24
- :ip_reasm,
25
- :queue_stats,
26
- :arp_match_ip]
27
-
28
- # enum ofp_action_type
29
- flags_32bit :actions_flag,
30
- [:output,
31
- :set_vlan_vid,
32
- :set_vlan_pcp,
33
- :strip_vlan,
34
- :set_ether_source_address,
35
- :set_ether_destination_address,
36
- :set_ip_source_address,
37
- :set_ip_destination_address,
38
- :set_ip_tos,
39
- :set_transport_source_port,
40
- :set_transport_destination_port,
41
- :enqueue]
42
-
43
- endian :big
44
-
45
- uint64 :datapath_id
46
- uint32 :n_buffers
47
- uint8 :n_tables
48
- uint24 :padding
49
- hide :padding
50
- capabilities :capabilities
51
- actions_flag :actions
52
- array :ports, type: :phy_port, read_until: :eof
53
-
54
- def empty?
55
- false
4
+ module OpenFlow10
5
+ # OpenFlow 1.0 Features Request and Reply message.
6
+ class Features
7
+ # OpenFlow 1.0 Features Request message.
8
+ class Request < OpenFlow::Message
9
+ # OpenFlow 1.0 Features Request message
10
+ class Format < BinData::Record
11
+ extend OpenFlow::Format
12
+
13
+ header version: 1, message_type: 5
14
+ string :body, value: ''
15
+
16
+ def user_data
17
+ body
18
+ end
56
19
  end
57
20
 
58
- def length
59
- 24 + ports.to_binary_s.length
21
+ def initialize(user_options = {})
22
+ validate_user_options user_options
23
+ @format = Format.new(header: parse_header_options(user_options))
60
24
  end
61
25
  end
62
- end
63
26
 
64
- OpenFlow::Message.factory(Reply, OpenFlow::FEATURES_REPLY) do
65
- def_delegators :body, :datapath_id
66
- def_delegator :body, :datapath_id, :dpid
67
- def_delegators :body, :n_buffers
68
- def_delegators :body, :n_tables
69
- def_delegators :body, :capabilities
70
- def_delegators :body, :actions
71
-
72
- def ports
73
- @format.snapshot.body.ports.map do |each|
74
- each.instance_variable_set :@datapath_id, datapath_id
75
- each
27
+ # OpenFlow 1.0 Features Reply message.
28
+ class Reply < OpenFlow::Message
29
+ # Message body of features reply.
30
+ class Body < BinData::Record
31
+ extend OpenFlow::Flags
32
+
33
+ # enum ofp_capabilities
34
+ flags_32bit :capabilities,
35
+ [:flow_stats,
36
+ :table_stats,
37
+ :port_stats,
38
+ :stp,
39
+ :reserved,
40
+ :ip_reasm,
41
+ :queue_stats,
42
+ :arp_match_ip]
43
+
44
+ # enum ofp_action_type
45
+ flags_32bit :actions_flag,
46
+ [:output,
47
+ :set_vlan_vid,
48
+ :set_vlan_pcp,
49
+ :strip_vlan,
50
+ :set_ether_source_address,
51
+ :set_ether_destination_address,
52
+ :set_ip_source_address,
53
+ :set_ip_destination_address,
54
+ :set_ip_tos,
55
+ :set_transport_source_port,
56
+ :set_transport_destination_port,
57
+ :enqueue]
58
+
59
+ endian :big
60
+
61
+ datapath_id :datapath_id
62
+ uint32 :n_buffers
63
+ uint8 :n_tables
64
+ uint24 :padding
65
+ hide :padding
66
+ capabilities :capabilities
67
+ actions_flag :actions
68
+ array :ports, type: :phy_port, read_until: :eof
69
+
70
+ def dpid
71
+ datapath_id
72
+ end
73
+
74
+ def empty?
75
+ false
76
+ end
77
+
78
+ def length
79
+ 24 + ports.to_binary_s.length
80
+ end
76
81
  end
77
- end
78
82
 
79
- def physical_ports
80
- ports.select do |each|
81
- each.port_no <= PortNumber::MAX
83
+ # OpenFlow 1.0 Features Reply message
84
+ class Format < BinData::Record
85
+ extend OpenFlow::Format
86
+
87
+ header version: 1, message_type: 6
88
+ body :body
89
+
90
+ def ports
91
+ body.snapshot.ports.map do |each|
92
+ each.instance_variable_set :@datapath_id, datapath_id
93
+ each
94
+ end
95
+ end
96
+
97
+ def physical_ports
98
+ ports.select do |each|
99
+ each.port_no <= PortNumber::MAX
100
+ end
101
+ end
82
102
  end
103
+
104
+ body_option :dpid
105
+ body_option :datapath_id
106
+ body_option :n_buffers
107
+ body_option :n_tables
108
+ body_option :capabilities
109
+ body_option :actions
110
+ body_option :ports
83
111
  end
84
112
  end
85
113
  end