pio 0.25.0 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +4 -0
  4. data/Rakefile +1 -1
  5. data/bin/terminal-notifier +16 -0
  6. data/features/open_flow10/bad_request.feature +35 -0
  7. data/features/open_flow10/bad_request.raw +0 -0
  8. data/features/open_flow10/barrier_reply.feature +4 -4
  9. data/features/open_flow10/barrier_request.feature +4 -4
  10. data/features/open_flow10/echo_reply.feature +13 -13
  11. data/features/open_flow10/echo_request.feature +6 -6
  12. data/features/open_flow10/enqueue.feature +17 -0
  13. data/features/open_flow10/features_reply.feature +2 -2
  14. data/features/open_flow10/features_request.feature +28 -28
  15. data/features/open_flow10/flow_mod.feature +5 -5
  16. data/features/open_flow10/flow_stats_reply.feature +12 -12
  17. data/features/open_flow10/flow_stats_request.feature +3 -3
  18. data/features/open_flow10/hello.feature +8 -15
  19. data/features/open_flow10/hello_failed.feature +69 -0
  20. data/features/open_flow10/hello_failed.raw +0 -0
  21. data/features/open_flow10/nxast_learn.raw +0 -0
  22. data/features/open_flow10/packet_in.feature +2 -2
  23. data/features/open_flow10/packet_out.feature +13 -13
  24. data/features/open_flow10/port_status.feature +1 -1
  25. data/features/open_flow10/send_out_port.feature +106 -0
  26. data/features/open_flow10/set_ether_destination_address.feature +16 -0
  27. data/features/open_flow10/set_ether_source_address.feature +16 -0
  28. data/features/open_flow10/set_ip_destination_address.feature +16 -0
  29. data/features/open_flow10/set_ip_source_address.feature +16 -0
  30. data/features/open_flow10/set_ip_tos.feature +16 -0
  31. data/features/open_flow10/set_transport_destination_port.feature +16 -0
  32. data/features/open_flow10/set_transport_source_port.feature +16 -0
  33. data/features/open_flow10/set_vlan_priority.feature +16 -0
  34. data/features/open_flow10/set_vlan_vid.feature +16 -0
  35. data/features/open_flow10/strip_vlan_header.feature +15 -0
  36. data/features/open_flow10/vendor_action.feature +14 -0
  37. data/features/open_flow13/bad_request.feature +35 -0
  38. data/features/open_flow13/bad_request.raw +0 -0
  39. data/features/open_flow13/echo_reply.feature +7 -7
  40. data/features/open_flow13/echo_request.feature +7 -7
  41. data/features/open_flow13/features_reply.feature +2 -2
  42. data/features/open_flow13/features_request.feature +28 -28
  43. data/features/open_flow13/flow_mod.feature +24 -24
  44. data/features/open_flow13/hello.feature +5 -5
  45. data/features/open_flow13/hello_failed.feature +69 -0
  46. data/features/open_flow13/hello_failed.raw +0 -0
  47. data/features/open_flow13/packet_in.feature +3 -3
  48. data/features/open_flow13/packet_out.feature +3 -3
  49. data/features/open_flow13/send_out_port.feature +101 -10
  50. data/features/open_flow13/table_stats_reply.raw +0 -0
  51. data/features/open_flow13/table_stats_request.raw +0 -0
  52. data/features/open_flow_read.feature +6 -0
  53. data/features/step_definitions/Gemfile +9 -0
  54. data/features/step_definitions/Gemfile.lock +76 -0
  55. data/features/step_definitions/Guardfile +4 -0
  56. data/features/step_definitions/LICENSE +675 -0
  57. data/features/step_definitions/README.md +7 -0
  58. data/features/step_definitions/Rakefile +10 -0
  59. data/features/step_definitions/dump_flows_steps.rb +13 -0
  60. data/features/step_definitions/packet_data_steps.rb +4 -0
  61. data/features/step_definitions/rest_api_steps.rb +40 -0
  62. data/features/step_definitions/show_stats_steps.rb +83 -0
  63. data/features/step_definitions/trema_steps.rb +33 -0
  64. data/features/step_definitions/virtual_link_steps.rb +8 -0
  65. data/lib/pio/open_flow.rb +5 -5
  66. data/lib/pio/open_flow/echo.rb +1 -1
  67. data/lib/pio/open_flow/error.rb +19 -0
  68. data/lib/pio/open_flow/format.rb +2 -1
  69. data/lib/pio/open_flow/hello_failed_code.rb +21 -0
  70. data/lib/pio/open_flow/open_flow_header.rb +11 -2
  71. data/lib/pio/open_flow/port.rb +69 -0
  72. data/lib/pio/open_flow10.rb +5 -0
  73. data/lib/pio/open_flow10/actions.rb +8 -6
  74. data/lib/pio/open_flow10/enqueue.rb +13 -13
  75. data/lib/pio/open_flow10/error.rb +28 -0
  76. data/lib/pio/open_flow10/error/bad_request.rb +66 -0
  77. data/lib/pio/open_flow10/error/error_type10.rb +26 -0
  78. data/lib/pio/open_flow10/error/hello_failed.rb +41 -0
  79. data/lib/pio/open_flow10/features.rb +6 -10
  80. data/lib/pio/open_flow10/flow_mod.rb +1 -1
  81. data/lib/pio/open_flow10/flow_stats_request.rb +1 -1
  82. data/lib/pio/open_flow10/hello.rb +2 -2
  83. data/lib/pio/open_flow10/match.rb +2 -2
  84. data/lib/pio/{open_flow/phy_port.rb → open_flow10/phy_port16.rb} +4 -4
  85. data/lib/pio/open_flow10/port16.rb +21 -0
  86. data/lib/pio/open_flow10/port_status.rb +1 -1
  87. data/lib/pio/open_flow10/send_out_port.rb +16 -40
  88. data/lib/pio/open_flow10/set_ether_address.rb +9 -8
  89. data/lib/pio/open_flow10/set_ip_address.rb +4 -4
  90. data/lib/pio/open_flow10/set_ip_tos.rb +4 -4
  91. data/lib/pio/open_flow10/set_transport_port.rb +12 -12
  92. data/lib/pio/open_flow10/set_vlan.rb +4 -4
  93. data/lib/pio/open_flow10/set_vlan_vid.rb +0 -12
  94. data/lib/pio/open_flow10/strip_vlan_header.rb +7 -7
  95. data/lib/pio/open_flow10/vendor_action.rb +33 -0
  96. data/lib/pio/open_flow13.rb +3 -0
  97. data/lib/pio/open_flow13/actions.rb +3 -3
  98. data/lib/pio/open_flow13/error.rb +28 -0
  99. data/lib/pio/open_flow13/error/bad_request.rb +66 -0
  100. data/lib/pio/open_flow13/error/error_type13.rb +37 -0
  101. data/lib/pio/open_flow13/error/hello_failed.rb +42 -0
  102. data/lib/pio/open_flow13/features_reply.rb +33 -33
  103. data/lib/pio/open_flow13/features_request.rb +3 -3
  104. data/lib/pio/open_flow13/flow_mod.rb +2 -2
  105. data/lib/pio/open_flow13/goto_table.rb +2 -0
  106. data/lib/pio/open_flow13/packet_out.rb +1 -1
  107. data/lib/pio/open_flow13/port32.rb +21 -0
  108. data/lib/pio/open_flow13/send_out_port.rb +3 -2
  109. data/lib/pio/version.rb +1 -1
  110. data/pio.gemspec +5 -5
  111. data/spec/pio/open_flow10/enqueue_spec.rb +22 -22
  112. data/spec/pio/open_flow10/error/hello_failed_spec.rb +26 -0
  113. data/spec/pio/open_flow10/flow_mod_spec.rb +6 -6
  114. data/spec/pio/open_flow10/flow_stats_request_spec.rb +1 -1
  115. data/spec/pio/open_flow10/hello_spec.rb +3 -3
  116. data/spec/pio/open_flow10/packet_out_spec.rb +33 -33
  117. data/spec/pio/{open_flow/phy_port_spec.rb → open_flow10/phy_port16_spec.rb} +7 -7
  118. data/spec/pio/open_flow10/send_out_port_spec.rb +28 -28
  119. data/spec/pio/open_flow10/set_ether_destination_address_spec.rb +2 -2
  120. data/spec/pio/open_flow10/set_ether_source_address_spec.rb +2 -2
  121. data/spec/pio/open_flow10/set_ip_destination_address_spec.rb +4 -4
  122. data/spec/pio/open_flow10/set_ip_source_address_spec.rb +4 -4
  123. data/spec/pio/open_flow10/set_ip_tos_spec.rb +4 -4
  124. data/spec/pio/open_flow10/set_transport_destination_port_spec.rb +11 -11
  125. data/spec/pio/open_flow10/set_transport_source_port_spec.rb +11 -11
  126. data/spec/pio/open_flow10/set_vlan_priority_spec.rb +4 -4
  127. data/spec/pio/open_flow10/set_vlan_vid_spec.rb +4 -4
  128. data/spec/pio/open_flow10/strip_vlan_header_spec.rb +6 -6
  129. data/spec/pio/open_flow13/error/bad_request_spec.rb +6 -0
  130. data/spec/pio/open_flow13/error/hello_failed_spec.rb +26 -0
  131. data/spec/pio/open_flow13/hello_spec.rb +3 -3
  132. data/spec/support/shared_examples_for_openflow_messages.rb +40 -27
  133. metadata +106 -16
  134. data/lib/pio/open_flow/port_number.rb +0 -39
@@ -1,7 +1,7 @@
1
1
  require 'bindata'
2
2
  require 'forwardable'
3
3
  require 'pio/monkey_patch/integer'
4
- require 'pio/open_flow/port_number'
4
+ require 'pio/open_flow10/port16'
5
5
 
6
6
  module Pio
7
7
  # An action to enqueue the packet on the specified queue attached to
@@ -11,9 +11,9 @@ module Pio
11
11
  class Format < BinData::Record
12
12
  endian :big
13
13
 
14
- uint16 :type, value: 11
15
- uint16 :message_length, value: 16
16
- port_number :port_number
14
+ uint16 :action_type, value: 11
15
+ uint16 :action_length, value: 16
16
+ port16 :port
17
17
  uint48 :padding
18
18
  hide :padding
19
19
  uint32 :queue_id
@@ -27,28 +27,28 @@ module Pio
27
27
 
28
28
  extend Forwardable
29
29
 
30
- def_delegators :@format, :type
31
- def_delegators :@format, :message_length
32
- def_delegators :@format, :port_number
30
+ def_delegators :@format, :action_type
31
+ def_delegator :@format, :action_length, :length
32
+ def_delegators :@format, :port
33
33
  def_delegators :@format, :queue_id
34
34
  def_delegator :@format, :to_binary_s, :to_binary
35
35
 
36
36
  def initialize(user_options)
37
- validate_port_number user_options
37
+ validate_port user_options
38
38
  validate_queue_id user_options
39
39
  @format = Format.new(user_options)
40
40
  end
41
41
 
42
42
  private
43
43
 
44
- def validate_port_number(user_options)
45
- port_number = user_options.fetch(:port_number)
46
- if port_number.is_a?(Symbol) && port_number != :in_port
44
+ def validate_port(user_options)
45
+ port = user_options.fetch(:port)
46
+ if port.is_a?(Symbol) && port != :in_port
47
47
  fail(ArgumentError,
48
- ':port_number must be a valid physical port or :in_port')
48
+ ':port must be a valid physical port or :in_port')
49
49
  end
50
50
  rescue KeyError
51
- raise ArgumentError, ':port_number is a mandatory option'
51
+ raise ArgumentError, ':port is a mandatory option'
52
52
  end
53
53
 
54
54
  def validate_queue_id(user_options)
@@ -0,0 +1,28 @@
1
+ require 'pio/open_flow10/error/error_type10'
2
+
3
+ module Pio
4
+ module OpenFlow10
5
+ # Error message parser
6
+ module Error
7
+ # Error message body parser.
8
+ class BodyParser < BinData::Record
9
+ endian :big
10
+ error_type10 :error_type
11
+ uint16 :error_code
12
+ end
13
+
14
+ def self.read(binary)
15
+ body = OpenFlowHeaderParser.read(binary).body
16
+ klass = case BodyParser.read(body).snapshot.error_type
17
+ when :hello_failed
18
+ HelloFailed
19
+ when :bad_request
20
+ BadRequest
21
+ else
22
+ fail 'Unknown error message.'
23
+ end
24
+ klass.read binary
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ require 'bindata'
2
+ require 'pio/open_flow/format'
3
+ require 'pio/open_flow/message'
4
+ require 'pio/open_flow10/error/error_type10'
5
+
6
+ module Pio
7
+ module OpenFlow10
8
+ module Error
9
+ # Bad request error.
10
+ class BadRequest < OpenFlow::Message
11
+ # Bad request error format.
12
+ class Format < BinData::Record
13
+ # Bad request error body.
14
+ class Body < BinData::Record
15
+ # enum ofp_bad_request_code
16
+ class BadRequestCode < BinData::Primitive
17
+ ERROR_CODES = {
18
+ bad_version: 0,
19
+ bad_type: 1,
20
+ bad_stats: 2,
21
+ bad_vendor: 3,
22
+ bad_subtype: 4,
23
+ permissions_error: 5,
24
+ bad_length: 6,
25
+ buffer_empty: 7,
26
+ buffer_unknown: 8
27
+ }
28
+
29
+ endian :big
30
+ uint16 :error_code
31
+
32
+ def get
33
+ ERROR_CODES.invert.fetch(error_code)
34
+ end
35
+
36
+ def set(value)
37
+ self.error_code = ERROR_CODES.fetch(value)
38
+ end
39
+ end
40
+
41
+ endian :big
42
+
43
+ error_type10 :error_type, value: -> { :bad_request }
44
+ bad_request_code :error_code
45
+ rest :raw_data
46
+
47
+ def length
48
+ 4 + raw_data.length
49
+ end
50
+ end
51
+
52
+ extend OpenFlow::Format
53
+
54
+ header version: 1, message_type: 1
55
+ body :body
56
+
57
+ def length
58
+ 8 + body.length
59
+ end
60
+ end
61
+
62
+ body_option :raw_data
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ module Pio
2
+ module OpenFlow10
3
+ # enum ofp_error_type
4
+ class ErrorType10 < BinData::Primitive
5
+ ERROR_TYPES = {
6
+ hello_failed: 0,
7
+ bad_request: 1,
8
+ bad_action: 2,
9
+ flow_mod_failed: 3,
10
+ port_mod_failed: 4,
11
+ queue_operation_failed: 5
12
+ }
13
+
14
+ endian :big
15
+ uint16 :error_type
16
+
17
+ def get
18
+ ERROR_TYPES.invert.fetch(error_type)
19
+ end
20
+
21
+ def set(value)
22
+ self.error_type = ERROR_TYPES.fetch(value)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,41 @@
1
+ require 'pio/open_flow/format'
2
+ require 'pio/open_flow/hello_failed_code'
3
+ require 'pio/open_flow/message'
4
+ require 'pio/open_flow10/error/error_type10'
5
+
6
+ module Pio
7
+ module OpenFlow10
8
+ module Error
9
+ # Hello failed error.
10
+ class HelloFailed < OpenFlow::Message
11
+ # Hello Failed error format.
12
+ class Format < BinData::Record
13
+ # Hello Failed error body.
14
+ class Body < BinData::Record
15
+ endian :big
16
+
17
+ error_type10 :error_type
18
+ hello_failed_code :error_code
19
+ rest :description
20
+
21
+ def length
22
+ 4 + description.length
23
+ end
24
+ end
25
+
26
+ extend OpenFlow::Format
27
+
28
+ header version: 1, message_type: 1
29
+ body :body
30
+
31
+ def length
32
+ 8 + body.length
33
+ end
34
+ end
35
+
36
+ body_option :error_code
37
+ body_option :description
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,12 +1,13 @@
1
1
  require 'pio/open_flow'
2
+ require 'pio/open_flow10/phy_port16'
2
3
 
3
4
  module Pio
4
5
  module OpenFlow10
5
- # OpenFlow 1.0 Features Request and Reply message.
6
+ # Features Request and Reply message.
6
7
  class Features
7
- # OpenFlow 1.0 Features Request message.
8
+ # Features Request message.
8
9
  class Request < OpenFlow::Message
9
- # OpenFlow 1.0 Features Request message
10
+ # Features Request message format.
10
11
  class Format < BinData::Record
11
12
  extend OpenFlow::Format
12
13
 
@@ -17,11 +18,6 @@ module Pio
17
18
  body
18
19
  end
19
20
  end
20
-
21
- def initialize(user_options = {})
22
- validate_user_options user_options
23
- @format = Format.new(header: parse_header_options(user_options))
24
- end
25
21
  end
26
22
 
27
23
  # OpenFlow 1.0 Features Reply message.
@@ -65,7 +61,7 @@ module Pio
65
61
  hide :padding
66
62
  capabilities :capabilities
67
63
  actions_flag :actions
68
- array :ports, type: :phy_port, read_until: :eof
64
+ array :ports, type: :phy_port16, read_until: :eof
69
65
 
70
66
  def dpid
71
67
  datapath_id
@@ -96,7 +92,7 @@ module Pio
96
92
 
97
93
  def physical_ports
98
94
  ports.select do |each|
99
- each.port_no <= PortNumber::MAX
95
+ each.port_no <= Port16::MAX
100
96
  end
101
97
  end
102
98
  end
@@ -49,7 +49,7 @@ module Pio
49
49
  uint32 :buffer_id
50
50
  uint16 :out_port
51
51
  flags :flags
52
- actions :actions, length: -> { header.message_length - 72 }
52
+ actions :actions, length: -> { header.length - 72 }
53
53
 
54
54
  def empty?
55
55
  false
@@ -19,7 +19,7 @@ module Pio
19
19
  uint8 :table_id, initial_value: 0xff
20
20
  string :padding, length: 1
21
21
  hide :padding
22
- port_number :out_port, initial_value: -> { :none }
22
+ port16 :out_port, initial_value: -> { :none }
23
23
  end
24
24
 
25
25
  # Message body of Flow Stats Request.
@@ -5,9 +5,9 @@ require 'pio/open_flow/message'
5
5
  module Pio
6
6
  # OpenFlow 1.0 messages
7
7
  module OpenFlow10
8
- # OpenFlow 1.0 Hello message
8
+ # Hello message
9
9
  class Hello < OpenFlow::Message
10
- # OpenFlow 1.0 Hello message format
10
+ # Hello message format
11
11
  class Format < BinData::Record
12
12
  extend OpenFlow::Format
13
13
 
@@ -48,7 +48,7 @@ module Pio
48
48
  BITS.each_with_object(Hash.new(0)) do |(key, bit), memo|
49
49
  next if flags & bit == 0
50
50
  if /(ip_source_address|ip_destination_address)(\d)/=~ key
51
- memo[$LAST_MATCH_INFO[1].intern] |= 1 << $LAST_MATCH_INFO[2].to_i
51
+ memo[$LAST_MATCH_INFO[1].to_sym] |= 1 << $LAST_MATCH_INFO[2].to_i
52
52
  else
53
53
  memo[key] = true
54
54
  end
@@ -141,7 +141,7 @@ module Pio
141
141
  if user_options.key?(each)
142
142
  memo[each] = 32 - IPv4Address.new(user_options[each]).prefixlen
143
143
  else
144
- memo["#{each}_all".intern] = true
144
+ memo["#{each}_all".to_sym] = true
145
145
  end
146
146
  end
147
147
  @format = MatchFormat.new({ wildcards: flags }.merge user_options)
@@ -2,10 +2,10 @@ require 'bindata'
2
2
  require 'pio/type/mac_address'
3
3
 
4
4
  module Pio
5
- module OpenFlow
5
+ module OpenFlow10
6
6
  # Description of a physical port
7
- class PhyPort < BinData::Record
8
- extend Flags
7
+ class PhyPort16 < BinData::Record
8
+ extend OpenFlow::Flags
9
9
 
10
10
  # enum ofp_port_config
11
11
  flags_32bit :port_config,
@@ -80,7 +80,7 @@ module Pio
80
80
  end
81
81
 
82
82
  def ss.local?
83
- port_no == PortNumber::NUMBERS[:local]
83
+ port_no == OpenFlow10::Port16.reserved_port_number(:local)
84
84
  end
85
85
  end
86
86
  end
@@ -0,0 +1,21 @@
1
+ require 'pio/open_flow/port'
2
+
3
+ module Pio
4
+ module OpenFlow10
5
+ # Port numbering (16bit).
6
+ class Port16 < OpenFlow::Port
7
+ port_size_in_bytes 16
8
+
9
+ max_port_number 0xff00
10
+
11
+ reserved_ports(in_port: 0xfff8,
12
+ table: 0xfff9,
13
+ normal: 0xfffa,
14
+ flood: 0xfffb,
15
+ all: 0xfffc,
16
+ controller: 0xfffd,
17
+ local: 0xfffe,
18
+ none: 0xffff)
19
+ end
20
+ end
21
+ end
@@ -28,7 +28,7 @@ module Pio
28
28
  reason :reason
29
29
  uint56 :padding
30
30
  hide :padding
31
- phy_port :desc
31
+ phy_port16 :desc
32
32
  end
33
33
 
34
34
  # OpenFlow 1.0 Flow Mod message format.
@@ -1,7 +1,7 @@
1
1
  require 'bindata'
2
2
  require 'forwardable'
3
3
  require 'pio/monkey_patch/integer'
4
- require 'pio/open_flow/port_number'
4
+ require 'pio/open_flow10/port16'
5
5
 
6
6
  module Pio
7
7
  module OpenFlow10
@@ -11,10 +11,10 @@ module Pio
11
11
  class Format < BinData::Record
12
12
  endian :big
13
13
 
14
- uint16 :type, value: 0
15
- uint16 :message_length, value: 8
16
- port_number :port_number
17
- uint16 :max_len, initial_value: 2**16 - 1
14
+ uint16 :action_type, value: 0
15
+ uint16 :action_length, value: 8
16
+ port16 :port
17
+ uint16 :max_length, initial_value: 2**16 - 1
18
18
  end
19
19
 
20
20
  def self.read(raw_data)
@@ -25,49 +25,25 @@ module Pio
25
25
 
26
26
  extend Forwardable
27
27
 
28
- def_delegators :@format, :message_length
29
- def_delegators :@format, :port_number
30
- def_delegators :@format, :max_len
28
+ def_delegators :@format, :action_type
29
+ def_delegator :@format, :action_length, :length
30
+ def_delegators :@format, :port
31
+ def_delegators :@format, :max_length
31
32
  def_delegator :@format, :to_binary_s, :to_binary
32
33
 
33
- # Creates an action to output a packet to a port.
34
- #
35
- # @example
36
- # SendOutPort.new(1)
37
- # SendOutPort.new(port_number: 1)
38
- # SendOutPort.new(port_number: :controller, max_len: 256)
39
- #
40
- # @param [Integer|Hash] user_options
41
- # the port number or the options hash to create this action
42
- # class instance with.
43
- #
44
- # @option user_options [Number] :port_number
45
- # port number an index into switch's physical port list. There
46
- # are also fake output ports. For example a port number set to
47
- # +:flood+ would output packets to all physical ports except
48
- # input port and ports disabled by STP.
49
- # @option user_options [Number] :max_len
50
- # the maximum number of bytes from a packet to send to
51
- # controller when port is set to +:controller+. A zero length
52
- # means no bytes of the packet should be sent. It defaults to
53
- # 64K.
54
- #
55
- # @raise [ArgumentError] if +:port_number+ is not an unsigned
56
- # 16-bit integer.
57
- # @raise [ArgumentError] if +:max_len+ is not an unsigned 16-bit integer.
58
- #
59
34
  # rubocop:disable MethodLength
60
35
  def initialize(user_options)
61
36
  options = if user_options.respond_to?(:to_i)
62
- { port_number: user_options.to_i }
63
- elsif PortNumber::NUMBERS.key?(user_options)
64
- { port_number: user_options }
37
+ { port: user_options.to_i }
38
+ elsif Port16.reserved_port_name?(user_options)
39
+ { port: user_options }
65
40
  else
66
41
  user_options
67
42
  end
68
- max_len = options[:max_len]
69
- if max_len && !max_len.unsigned_16bit?
70
- fail ArgumentError, 'The max_len should be an unsigned 16bit integer.'
43
+ max_length = options[:max_length]
44
+ if max_length && !max_length.unsigned_16bit?
45
+ fail(ArgumentError,
46
+ 'The max_length should be an unsigned 16bit integer.')
71
47
  end
72
48
  @format = Format.new(options)
73
49
  end