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
@@ -25,6 +25,7 @@ module Pio
25
25
  def_delegators :@format, :instruction_type
26
26
  def_delegators :@format, :instruction_length
27
27
  def_delegators :@format, :table_id
28
+ def_delegators :@format, :to_binary_s
28
29
 
29
30
  def initialize(table_id)
30
31
  @format = Format.new(table_id: table_id)
@@ -1,113 +1,83 @@
1
- require 'bindata'
2
- require 'forwardable'
3
1
  require 'pio/open_flow'
4
- require 'pio/parse_error'
5
2
 
6
3
  # Base module.
7
4
  module Pio
8
- remove_const :Hello
9
-
10
- # OpenFlow 1.3 Hello message parser and generator
11
- class Hello
12
- # ofp_hello_elem_header and value
13
- class Element < BinData::Record
5
+ # OpenFlow 1.0 messages
6
+ module OpenFlow13
7
+ # OpenFlow 1.3 Hello message parser and generator
8
+ class Hello < OpenFlow::Message
14
9
  VERSION_BITMAP = 1
15
10
 
16
- endian :big
11
+ # ofp_hello_elem_header and value
12
+ class Element < BinData::Record
13
+ endian :big
17
14
 
18
- uint16 :element_type
19
- uint16 :element_length
20
- choice :element_value, selection: :chooser do
21
- string 'unknown', read_length: -> { element_length - 4 }
22
- uint32 'version_bitmap'
23
- end
15
+ uint16 :element_type
16
+ uint16 :element_length
17
+ choice :element_value, selection: :chooser do
18
+ string 'unknown', read_length: -> { element_length - 4 }
19
+ uint32 'version_bitmap'
20
+ end
24
21
 
25
- def version_bitmap?
26
- element_type == VERSION_BITMAP
27
- end
22
+ def version_bitmap?
23
+ element_type == VERSION_BITMAP
24
+ end
28
25
 
29
- private
26
+ private
30
27
 
31
- def chooser
32
- version_bitmap? ? 'version_bitmap' : 'unknown'
28
+ def chooser
29
+ version_bitmap? ? 'version_bitmap' : 'unknown'
30
+ end
33
31
  end
34
- end
35
32
 
36
- # OpenFlow 1.3 Hello message body.
37
- class Body < BinData::Record
38
- array :elements, type: :element, read_until: :eof
33
+ # OpenFlow 1.3 Hello message body.
34
+ class Body < BinData::Record
35
+ array :elements, type: :element, read_until: :eof
39
36
 
40
- def length
41
- if elements.empty?
42
- 0
43
- else
44
- elements.length * 4 + 4
37
+ def length
38
+ if elements.empty?
39
+ 0
40
+ else
41
+ elements.length * 4 + 4
42
+ end
45
43
  end
46
44
  end
47
- end
48
-
49
- # OpenFlow 1.3 Hello message format
50
- class Format < BinData::Record
51
- extend Forwardable
52
45
 
53
- endian :big
46
+ # OpenFlow 1.3 Hello message format
47
+ class Format < BinData::Record
48
+ extend OpenFlow::Format
54
49
 
55
- open_flow_header :open_flow_header,
56
- ofp_version_value: 4, message_type_value: 0
57
- body :body
50
+ header version: 4, message_type: 0
51
+ body :body
58
52
 
59
- def_delegators :open_flow_header, :ofp_version
60
- def_delegators :open_flow_header, :message_type
61
- def_delegators :open_flow_header, :message_length
62
- def_delegators :open_flow_header, :transaction_id
63
- def_delegator :open_flow_header, :transaction_id, :xid
64
- def_delegators :body, :elements
65
-
66
- def supported_versions
67
- supported_versions_list.map do |each|
68
- "open_flow1#{each - 1}".to_sym
53
+ def supported_versions
54
+ supported_versions_list.map do |each|
55
+ "open_flow1#{each - 1}".to_sym
56
+ end
69
57
  end
70
- end
71
58
 
72
- alias_method :to_binary, :to_binary_s
59
+ private
73
60
 
74
- private
75
-
76
- def supported_versions_list
77
- (1..32).each_with_object([]) do |each, result|
78
- result << each if (version_bitmap >> each & 1) == 1
61
+ def supported_versions_list
62
+ (1..32).each_with_object([]) do |each, result|
63
+ result << each if (version_bitmap >> each & 1) == 1
64
+ end
79
65
  end
80
- end
81
-
82
- def version_bitmap
83
- bitmap = elements.find(&:version_bitmap?)
84
- bitmap ? bitmap.element_value : 0
85
- end
86
- end
87
66
 
88
- def self.read(raw_data)
89
- allocate.tap do |message|
90
- message.instance_variable_set(:@format, Format.read(raw_data))
67
+ def version_bitmap
68
+ bitmap = elements.detect(&:version_bitmap?)
69
+ bitmap ? bitmap.element_value : 0
70
+ end
91
71
  end
92
- rescue BinData::ValidityError
93
- raise Pio::ParseError, 'Invalid Hello 1.3 message.'
94
- end
95
72
 
96
- def initialize(user_attrs = {})
97
- unknown_keywords = user_attrs.keys - [:transaction_id, :xid]
98
- unless unknown_keywords.empty?
99
- fail "Unknown keyword: #{unknown_keywords.first}"
73
+ def initialize(user_options = {})
74
+ validate_user_options user_options
75
+ header_options = parse_header_options(user_options)
76
+ body_options = { elements: [{ element_type: VERSION_BITMAP,
77
+ element_length: 8,
78
+ element_value: 0b10000 }] }
79
+ @format = Format.new(header: header_options, body: body_options)
100
80
  end
101
-
102
- header_attrs = OpenFlowHeader::Options.parse(user_attrs)
103
- body_attrs = { elements: [{ element_type: 1,
104
- element_length: 8,
105
- element_value: 16 }] }
106
- @format = Format.new(open_flow_header: header_attrs, body: body_attrs)
107
- end
108
-
109
- def method_missing(method, *args, &block)
110
- @format.__send__ method, *args, &block
111
81
  end
112
82
  end
113
83
  end
@@ -13,6 +13,7 @@ module Pio
13
13
  # OpenFlow eXtensible Match (OXM)
14
14
  class Match
15
15
  OXM_CLASS_OPENFLOW_BASIC = 0x8000
16
+ OXM_CLASS_EXPERIMENTER = 0xFFFF
16
17
 
17
18
  # The value of OXM_OF_IN_PORT match field.
18
19
  class InPort < BinData::Record
@@ -548,17 +549,30 @@ module Pio
548
549
 
549
550
  # OXM format
550
551
  class Oxm < BinData::Record
551
- # OXM match field.
552
+ # Experimenter part, data will use oxm_length
553
+ class Experimenter < BinData::Record
554
+ endian :big
555
+
556
+ bit7 :oxm_field
557
+ bit1 :oxm_hasmask
558
+ uint8 :oxm_length, value: -> { data.length + 4 }
559
+ uint32 :experimenter
560
+ string :data, read_length: -> { oxm_length - 4 }
561
+
562
+ def length
563
+ oxm_length + 2
564
+ end
565
+ end
566
+
552
567
  # rubocop:disable ClassLength
553
- class MatchField < BinData::Record
568
+ # OpenflowBasic part, tlv_value will use oxm_field, oxm_hasmask
569
+ class OpenflowBasic < BinData::Record
554
570
  endian :big
555
571
 
556
- uint16 :oxm_class, value: OXM_CLASS_OPENFLOW_BASIC
557
572
  bit7 :oxm_field
558
573
  bit1 :oxm_hasmask
559
574
  uint8 :oxm_length, value: -> { tlv_value.length }
560
575
  choice :tlv_value,
561
- read_length: :oxm_length,
562
576
  selection: :choose_tlv_value do
563
577
  in_port InPort
564
578
  metadata Metadata
@@ -603,7 +617,7 @@ module Pio
603
617
  end
604
618
 
605
619
  def length
606
- tlv_value.length + 4
620
+ tlv_value.length + 2
607
621
  end
608
622
 
609
623
  def masked?
@@ -709,6 +723,44 @@ module Pio
709
723
  end
710
724
  # rubocop:enable MethodLength
711
725
 
726
+ # OXM match field.
727
+ class MatchField < BinData::Record
728
+ endian :big
729
+
730
+ uint16 :oxm_class, initial_value: OXM_CLASS_OPENFLOW_BASIC
731
+ choice :class_payload, selection: :oxm_class do
732
+ OpenflowBasic OXM_CLASS_OPENFLOW_BASIC
733
+ Experimenter OXM_CLASS_EXPERIMENTER
734
+ end
735
+
736
+ def oxm_field
737
+ class_payload.oxm_field
738
+ end
739
+
740
+ def masked?
741
+ class_payload.oxm_hasmask == 1
742
+ end
743
+
744
+ def oxm_length
745
+ class_payload.oxm_length
746
+ end
747
+
748
+ def length
749
+ class_payload.length + 2
750
+ end
751
+
752
+ def method_missing(method, *args, &block)
753
+ case oxm_class
754
+ when OXM_CLASS_OPENFLOW_BASIC
755
+ return class_payload.tlv_value.__send__(method, *args, &block)
756
+ when OXM_CLASS_EXPERIMENTER
757
+ return class_payload.__send__(method, *args, &block)
758
+ else
759
+ fail NoMethodError, method.to_s
760
+ end
761
+ end
762
+ end
763
+
712
764
  endian :big
713
765
 
714
766
  uint16 :match_type, value: MATCH_TYPE_OXM
@@ -724,13 +776,18 @@ module Pio
724
776
  match_length + padding_length
725
777
  end
726
778
 
779
+ # rubocop:disable Next
727
780
  def method_missing(method, *args, &block)
728
781
  match_fields.each do |each|
729
- next unless each.tlv_value.respond_to?(method)
730
- return each.tlv_value.__send__(method, *args, &block)
782
+ if each.oxm_class == OXM_CLASS_OPENFLOW_BASIC
783
+ next unless each.class_payload.tlv_value.respond_to?(method)
784
+ return each.class_payload.tlv_value.__send__(
785
+ method, *args, &block)
786
+ end
731
787
  end
732
788
  fail NoMethodError, method.to_s
733
789
  end
790
+ # rubocop:enable Next
734
791
 
735
792
  private
736
793
 
@@ -765,8 +822,9 @@ module Pio
765
822
  :icmpv4_type, :icmpv4_code, :arp_op].each do |each|
766
823
  next unless user_attrs.key?(each)
767
824
  klass = Match.const_get(each.to_s.split('_').map(&:capitalize).join)
768
- @match_fields << { oxm_field: klass.const_get(:OXM_FIELD),
769
- tlv_value: { each => user_attrs.fetch(each) } }
825
+ @match_fields << { class_payload:
826
+ { oxm_field: klass.const_get(:OXM_FIELD),
827
+ tlv_value: { each => user_attrs.fetch(each) } } }
770
828
  end
771
829
 
772
830
  [:metadata, :ether_destination_address, :ether_source_address,
@@ -778,11 +836,11 @@ module Pio
778
836
  next unless user_attrs.key?(each)
779
837
  klass = Match.const_get(each.to_s.split('_').map(&:capitalize).join)
780
838
  mask_key = "#{each}_mask".to_sym
781
- @match_fields <<
839
+ @match_fields << { class_payload:
782
840
  { oxm_field: klass.const_get(:OXM_FIELD),
783
841
  oxm_hasmask: user_attrs.key?(mask_key) ? 1 : 0,
784
842
  tlv_value: { each => user_attrs[each],
785
- mask_key => user_attrs[mask_key] } }
843
+ mask_key => user_attrs[mask_key] } } }
786
844
  end
787
845
  end
788
846
  # rubocop:enable MethodLength
@@ -24,6 +24,7 @@ module Pio
24
24
  def_delegators :@format, :instruction_type
25
25
  def_delegators :@format, :instruction_length
26
26
  def_delegators :@format, :meter_id
27
+ def_delegators :@format, :to_binary_s
27
28
 
28
29
  def initialize(meter_id)
29
30
  @format = Format.new(meter_id: meter_id)
@@ -1,29 +1,30 @@
1
+ require 'pio/open_flow'
2
+ require 'pio/open_flow13/match'
3
+ require 'pio/parser'
4
+
1
5
  # Base module.
2
6
  module Pio
3
- remove_const :PacketIn
4
-
5
- # OpenFlow 1.3 PacketIn message parser and generator
6
- class PacketIn
7
- # OpenFlow 1.3 PacketIn message format
8
- class Format < BinData::Record
9
- # OpenFlow 1.3 PacketIn message body
10
- class Body < BinData::Record
11
- # Why is this packet being sent to the controller?
12
- # (enum ofp_packet_in_reason)
13
- class Reason < BinData::Primitive
14
- REASONS = { no_match: 0, action: 1, invalid_ttl: 2 }
15
-
16
- uint8 :reason
17
-
18
- def get
19
- REASONS.invert.fetch(reason)
20
- end
7
+ module OpenFlow13
8
+ # OpenFlow 1.3 PacketIn message parser and generator
9
+ class PacketIn < OpenFlow::Message
10
+ # Why is this packet being sent to the controller?
11
+ # (enum ofp_packet_in_reason)
12
+ class Reason < BinData::Primitive
13
+ REASONS = { no_match: 0, action: 1, invalid_ttl: 2 }
14
+
15
+ uint8 :reason
16
+
17
+ def get
18
+ REASONS.invert.fetch(reason)
19
+ end
21
20
 
22
- def set(value)
23
- self.reason = REASONS.fetch(value)
24
- end
21
+ def set(value)
22
+ self.reason = REASONS.fetch(value)
25
23
  end
24
+ end
26
25
 
26
+ # OpenFlow 1.3 PacketIn message body
27
+ class Body < BinData::Record
27
28
  endian :big
28
29
 
29
30
  uint32 :buffer_id
@@ -44,44 +45,31 @@ module Pio
44
45
  @data ||= Pio::Parser.read(raw_data)
45
46
  end
46
47
 
48
+ def in_port
49
+ match.in_port
50
+ end
51
+
47
52
  def method_missing(method, *args)
48
53
  data.__send__(method, *args).snapshot
49
54
  end
50
55
  end
51
56
 
52
- extend Forwardable
53
-
54
- endian :big
55
-
56
- open_flow_header :open_flow_header,
57
- ofp_version_value: 4, message_type_value: 10
58
- body :body
59
-
60
- def_delegators :open_flow_header, :ofp_version
61
- def_delegators :open_flow_header, :message_type
62
- def_delegators :open_flow_header, :message_length
63
- def_delegators :open_flow_header, :transaction_id
64
- def_delegator :open_flow_header, :transaction_id, :xid
57
+ # OpenFlow 1.3 PacketIn message format
58
+ class Format < BinData::Record
59
+ extend OpenFlow::Format
65
60
 
66
- def method_missing(method, *args, &block)
67
- body.__send__ method, *args, &block
68
- end
69
- end
61
+ header version: 4, message_type: 10
62
+ body :body
70
63
 
71
- def self.read(raw_data)
72
- allocate.tap do |message|
73
- message.instance_variable_set(:@format, Format.read(raw_data))
64
+ attr_accessor :datapath_id
65
+ alias_method :dpid, :datapath_id
66
+ alias_method :dpid=, :datapath_id=
74
67
  end
75
- end
76
-
77
- def initialize(user_attrs = {})
78
- header_attrs = OpenFlowHeader::Options.parse(user_attrs)
79
- body_attrs = { raw_data: user_attrs[:raw_data] }
80
- @format = Format.new(open_flow_header: header_attrs, body: body_attrs)
81
- end
82
68
 
83
- def method_missing(method, *args, &block)
84
- @format.__send__ method, *args, &block
69
+ body_option :buffer_id
70
+ body_option :in_port
71
+ body_option :reason
72
+ body_option :raw_data
85
73
  end
86
74
  end
87
75
  end
@@ -1,90 +1,65 @@
1
- require 'bindata'
1
+ require 'pio/open_flow'
2
2
  require 'pio/open_flow13/actions'
3
3
  require 'pio/open_flow13/buffer_id'
4
4
 
5
5
  # Base module.
6
6
  module Pio
7
- remove_const :PacketOut
8
-
9
- # OpenFlow 1.3 PacketOut message parser and generator
10
- class PacketOut
11
- # Packet's input port or :controller
12
- class InPort < BinData::Primitive
13
- CONTROLLER = 0xfffffffd
14
-
15
- endian :big
16
- uint32 :in_port
17
-
18
- def get
19
- (in_port == CONTROLLER) ? :controller : in_port
20
- end
21
-
22
- def set(value)
23
- self.in_port = (value == :controller ? NO_CONTROLLER : value)
24
- end
25
- end
26
-
27
- # OpenFlow 1.3 PacketOut message body
28
- class Body < BinData::Record
29
- endian :big
30
-
31
- buffer_id :buffer_id
32
- in_port :in_port
33
- uint16 :actions_length, initial_value: -> { actions.binary.length }
34
- string :padding, length: 6
35
- actions :actions, length: :actions_length
36
- string :raw_data, read_length: -> { message_length - 24 - actions_length }
37
-
38
- def length
39
- 10 + padding.length + actions_length + raw_data.length
40
- end
41
-
42
- def data
43
- @data ||= Pio::Parser.read(raw_data)
7
+ module OpenFlow13
8
+ # OpenFlow 1.3 PacketOut message parser and generator
9
+ class PacketOut < OpenFlow::Message
10
+ # Packet's input port or :controller
11
+ class InPort < BinData::Primitive
12
+ CONTROLLER = 0xfffffffd
13
+
14
+ endian :big
15
+ uint32 :in_port
16
+
17
+ def get
18
+ (in_port == CONTROLLER) ? :controller : in_port
19
+ end
20
+
21
+ def set(value)
22
+ self.in_port = (value == :controller ? NO_CONTROLLER : value)
23
+ end
44
24
  end
45
25
 
46
- def method_missing(method, *args)
47
- data.__send__(method, *args).snapshot
26
+ # OpenFlow 1.3 PacketOut message body
27
+ class Body < BinData::Record
28
+ endian :big
29
+
30
+ buffer_id :buffer_id
31
+ in_port :in_port
32
+ uint16 :actions_length, initial_value: -> { actions.binary.length }
33
+ string :padding, length: 6
34
+ actions :actions, length: :actions_length
35
+ string :raw_data,
36
+ read_length: -> { message_length - 24 - actions_length }
37
+
38
+ def length
39
+ 10 + padding.length + actions_length + raw_data.length
40
+ end
41
+
42
+ def data
43
+ @data ||= Pio::Parser.read(raw_data)
44
+ end
45
+
46
+ def method_missing(method, *args)
47
+ data.__send__(method, *args).snapshot
48
+ end
48
49
  end
49
- end
50
-
51
- # OpenFlow 1.3 PacketOut message body
52
- class Format < BinData::Record
53
- extend Forwardable
54
50
 
55
- endian :big
51
+ # OpenFlow 1.3 PacketOut message body
52
+ class Format < BinData::Record
53
+ extend OpenFlow::Format
56
54
 
57
- open_flow_header :open_flow_header,
58
- ofp_version_value: 4, message_type_value: 13
59
- body :body
60
-
61
- def_delegators :open_flow_header, :ofp_version
62
- def_delegators :open_flow_header, :message_type
63
- def_delegators :open_flow_header, :message_length
64
- def_delegators :open_flow_header, :transaction_id
65
- def_delegator :open_flow_header, :transaction_id, :xid
66
-
67
- def method_missing(method, *args, &block)
68
- body.__send__ method, *args, &block
55
+ header version: 4, message_type: 13
56
+ body :body
69
57
  end
70
- end
71
-
72
- def self.read(raw_data)
73
- allocate.tap do |message|
74
- message.instance_variable_set(:@format, Format.read(raw_data))
75
- end
76
- end
77
-
78
- def initialize(user_attrs = {})
79
- header_attrs = OpenFlowHeader::Options.parse(user_attrs)
80
- body_attrs = { actions: user_attrs[:actions],
81
- raw_data: user_attrs[:raw_data] }
82
- @format = Format.new(open_flow_header: header_attrs,
83
- body: body_attrs)
84
- end
85
58
 
86
- def method_missing(method, *args, &block)
87
- @format.__send__ method, *args, &block
59
+ body_option :buffer_id
60
+ body_option :in_port
61
+ body_option :actions
62
+ body_option :raw_data
88
63
  end
89
64
  end
90
65
  end