pio 0.20.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Rakefile +2 -2
  4. data/features/open_flow13/match.feature +370 -0
  5. data/features/open_flow13/oxm_ether_destination_field.raw +0 -0
  6. data/features/open_flow13/oxm_ether_source_field.raw +0 -0
  7. data/features/open_flow13/oxm_ether_type_field.raw +0 -0
  8. data/features/open_flow13/oxm_in_phy_port_field.raw +0 -0
  9. data/features/open_flow13/oxm_in_port_field.raw +0 -0
  10. data/features/open_flow13/oxm_ipv4_destination_field.raw +0 -0
  11. data/features/open_flow13/oxm_ipv4_source_field.raw +0 -0
  12. data/features/open_flow13/oxm_ipv6_destination_field.raw +0 -0
  13. data/features/open_flow13/oxm_ipv6_source_field.raw +0 -0
  14. data/features/open_flow13/oxm_masked_ether_destination_field.raw +0 -0
  15. data/features/open_flow13/oxm_masked_ether_source_field.raw +0 -0
  16. data/features/open_flow13/oxm_masked_ipv4_destination_field.raw +0 -0
  17. data/features/open_flow13/oxm_masked_ipv4_source_field.raw +0 -0
  18. data/features/open_flow13/oxm_masked_ipv6_destination_field.raw +0 -0
  19. data/features/open_flow13/oxm_masked_ipv6_source_field.raw +0 -0
  20. data/features/open_flow13/oxm_metadata_field.raw +0 -0
  21. data/features/open_flow13/oxm_metadata_masked_field.raw +0 -0
  22. data/features/open_flow13/oxm_no_fields.raw +0 -0
  23. data/features/open_flow13/oxm_tcp_destination_field.raw +0 -0
  24. data/features/open_flow13/oxm_tcp_field.raw +0 -0
  25. data/features/open_flow13/oxm_tcp_source_field.raw +0 -0
  26. data/features/open_flow13/oxm_udp_destination_field.raw +0 -0
  27. data/features/open_flow13/oxm_udp_field.raw +0 -0
  28. data/features/open_flow13/oxm_udp_source_field.raw +0 -0
  29. data/lib/pio/ipv4_header.rb +0 -2
  30. data/lib/pio/open_flow/message.rb +18 -54
  31. data/lib/pio/open_flow10/packet_in.rb +1 -1
  32. data/lib/pio/open_flow13/match.rb +452 -0
  33. data/lib/pio/open_flow13.rb +7 -0
  34. data/lib/pio/type/ipv6_address.rb +21 -0
  35. data/lib/pio/version.rb +1 -1
  36. data/pio.gemspec +8 -8
  37. data/spec/pio/mac_spec.rb +2 -2
  38. data/spec/pio/open_flow13/match_spec.rb +387 -0
  39. data/spec/pio/packet_out_spec.rb +1 -2
  40. metadata +73 -19
@@ -0,0 +1,452 @@
1
+ require 'bindata'
2
+ require 'pio/type/ip_address'
3
+ require 'pio/type/ipv6_address'
4
+ require 'pio/type/mac_address'
5
+
6
+ # Base module.
7
+ module Pio
8
+ # OpenFlow 1.3.
9
+ module OpenFlow13
10
+ # OFPMT_OXM
11
+ MATCH_TYPE_OXM = 1
12
+
13
+ # OpenFlow eXtensible Match (OXM)
14
+ class Match
15
+ OXM_CLASS_OPENFLOW_BASIC = 0x8000
16
+
17
+ # The value of OXM_OF_IN_PORT match field.
18
+ class InPort < BinData::Record
19
+ OXM_FIELD = 0
20
+
21
+ endian :big
22
+
23
+ uint32 :in_port
24
+
25
+ def length
26
+ 4
27
+ end
28
+ end
29
+
30
+ # The value of OXM_OF_ETH_DST match field.
31
+ class EtherDestinationAddress < BinData::Record
32
+ OXM_FIELD = 3
33
+
34
+ endian :big
35
+
36
+ mac_address :ether_destination_address
37
+
38
+ def length
39
+ 6
40
+ end
41
+ end
42
+
43
+ # The value of OXM_OF_ETH_SRC match field.
44
+ class EtherSourceAddress < BinData::Record
45
+ OXM_FIELD = 4
46
+
47
+ endian :big
48
+
49
+ mac_address :ether_source_address
50
+
51
+ def length
52
+ 6
53
+ end
54
+ end
55
+
56
+ # Masked OXM_OF_ETH_DST match field.
57
+ class MaskedEtherDestinationAddress < BinData::Record
58
+ endian :big
59
+
60
+ mac_address :ether_destination_address
61
+ mac_address :ether_destination_address_mask
62
+
63
+ def length
64
+ 12
65
+ end
66
+ end
67
+
68
+ # Masked OXM_OF_ETH_SRC match field.
69
+ class MaskedEtherSourceAddress < BinData::Record
70
+ endian :big
71
+
72
+ mac_address :ether_source_address
73
+ mac_address :ether_source_address_mask
74
+
75
+ def length
76
+ 12
77
+ end
78
+ end
79
+
80
+ # The value of OXM_OF_ETH_TYPE match field.
81
+ class EtherType < BinData::Record
82
+ OXM_FIELD = 5
83
+
84
+ endian :big
85
+
86
+ uint16 :ether_type
87
+
88
+ def length
89
+ 2
90
+ end
91
+ end
92
+
93
+ # The value of OXM_OF_IP_PROTO
94
+ class IpProtocol < BinData::Record
95
+ OXM_FIELD = 10
96
+
97
+ endian :big
98
+
99
+ uint8 :ip_protocol
100
+
101
+ def length
102
+ 1
103
+ end
104
+ end
105
+
106
+ # The value of OXM_OF_IPV4_SRC
107
+ class Ipv4SourceAddress < BinData::Record
108
+ OXM_FIELD = 11
109
+
110
+ endian :big
111
+
112
+ ip_address :ipv4_source_address
113
+
114
+ def length
115
+ 4
116
+ end
117
+ end
118
+
119
+ # The value of masked OXM_OF_IPV4_SRC
120
+ class MaskedIpv4SourceAddress < BinData::Record
121
+ OXM_FIELD = 11
122
+
123
+ endian :big
124
+ ip_address :ipv4_source_address
125
+ ip_address :ipv4_source_address_mask
126
+
127
+ def length
128
+ 8
129
+ end
130
+ end
131
+
132
+ # The value of OXM_OF_IPV4_DST
133
+ class Ipv4DestinationAddress < BinData::Record
134
+ OXM_FIELD = 12
135
+
136
+ endian :big
137
+
138
+ ip_address :ipv4_destination_address
139
+
140
+ def length
141
+ 4
142
+ end
143
+ end
144
+
145
+ # The value of masked OXM_OF_IPV4_DST
146
+ class MaskedIpv4DestinationAddress < BinData::Record
147
+ OXM_FIELD = 12
148
+
149
+ endian :big
150
+ ip_address :ipv4_destination_address
151
+ ip_address :ipv4_destination_address_mask
152
+
153
+ def length
154
+ 8
155
+ end
156
+ end
157
+
158
+ # The value of OXM_OF_TCP_SRC
159
+ class TcpSourcePort < BinData::Record
160
+ OXM_FIELD = 13
161
+
162
+ endian :big
163
+
164
+ uint16 :tcp_source_port
165
+
166
+ def length
167
+ 16
168
+ end
169
+ end
170
+
171
+ # The value of OXM_OF_TCP_DST
172
+ class TcpDestinationPort < BinData::Record
173
+ OXM_FIELD = 14
174
+
175
+ endian :big
176
+
177
+ uint16 :tcp_destination_port
178
+
179
+ def length
180
+ 16
181
+ end
182
+ end
183
+
184
+ # The value of OXM_OF_UDP_SRC
185
+ class UdpSourcePort < BinData::Record
186
+ OXM_FIELD = 15
187
+
188
+ endian :big
189
+
190
+ uint16 :udp_source_port
191
+
192
+ def length
193
+ 16
194
+ end
195
+ end
196
+
197
+ # The value of OXM_OF_UDP_SRC
198
+ class UdpDestinationPort < BinData::Record
199
+ OXM_FIELD = 16
200
+
201
+ endian :big
202
+
203
+ uint16 :udp_destination_port
204
+
205
+ def length
206
+ 16
207
+ end
208
+ end
209
+
210
+ # The value of OXM_OF_IPV6_SRC
211
+ class Ipv6SourceAddress < BinData::Record
212
+ OXM_FIELD = 26
213
+
214
+ endian :big
215
+
216
+ ipv6_address :ipv6_source_address
217
+
218
+ def length
219
+ 128
220
+ end
221
+ end
222
+
223
+ # The value of masked OXM_OF_IPV6_SRC
224
+ class MaskedIpv6SourceAddress < BinData::Record
225
+ OXM_FIELD = 26
226
+
227
+ endian :big
228
+
229
+ ipv6_address :ipv6_source_address
230
+ ipv6_address :ipv6_source_address_mask
231
+
232
+ def length
233
+ 256
234
+ end
235
+ end
236
+
237
+ # The value of OXM_OF_IPV6_DST
238
+ class Ipv6DestinationAddress < BinData::Record
239
+ OXM_FIELD = 27
240
+
241
+ endian :big
242
+
243
+ ipv6_address :ipv6_destination_address
244
+
245
+ def length
246
+ 128
247
+ end
248
+ end
249
+
250
+ # The value of OXM_OF_IPV6_DST
251
+ class MaskedIpv6DestinationAddress < BinData::Record
252
+ OXM_FIELD = 27
253
+
254
+ endian :big
255
+
256
+ ipv6_address :ipv6_destination_address
257
+ ipv6_address :ipv6_destination_address_mask
258
+
259
+ def length
260
+ 256
261
+ end
262
+ end
263
+
264
+ # OXM format
265
+ class Format < BinData::Record
266
+ # OXM match field.
267
+ class MatchField < BinData::Record
268
+ endian :big
269
+
270
+ uint16 :oxm_class, value: OXM_CLASS_OPENFLOW_BASIC
271
+ bit7 :oxm_field
272
+ bit1 :oxm_hasmask
273
+ uint8 :oxm_length, value: -> { tlv_value.length }
274
+ choice :tlv_value,
275
+ read_length: :oxm_length,
276
+ selection: :choose_tlv_value do
277
+ in_port InPort
278
+ ether_destination_address EtherDestinationAddress
279
+ masked_ether_destination_address MaskedEtherDestinationAddress
280
+ ether_source_address EtherSourceAddress
281
+ masked_ether_source_address MaskedEtherSourceAddress
282
+ ether_type EtherType
283
+ ipv4_source_address Ipv4SourceAddress
284
+ masked_ipv4_source_address MaskedIpv4SourceAddress
285
+ ipv4_destination_address Ipv4DestinationAddress
286
+ masked_ipv4_destination_address MaskedIpv4DestinationAddress
287
+ ip_protocol IpProtocol
288
+ tcp_source_port TcpSourcePort
289
+ tcp_destination_port TcpDestinationPort
290
+ udp_source_port UdpSourcePort
291
+ udp_destination_port UdpDestinationPort
292
+ ipv6_source_address Ipv6SourceAddress
293
+ masked_ipv6_source_address MaskedIpv6SourceAddress
294
+ ipv6_destination_address Ipv6DestinationAddress
295
+ masked_ipv6_destination_address MaskedIpv6DestinationAddress
296
+ end
297
+
298
+ def length
299
+ tlv_value.length + 4
300
+ end
301
+
302
+ def masked?
303
+ oxm_hasmask == 1
304
+ end
305
+
306
+ def method_missing(method, *args, &block)
307
+ tlv_value.__send__ method, *args, &block
308
+ end
309
+
310
+ private
311
+
312
+ # rubocop:disable MethodLength
313
+ # rubocop:disable CyclomaticComplexity
314
+ # rubocop:disable PerceivedComplexity
315
+ # rubocop:disable AbcSize
316
+ def choose_tlv_value
317
+ case oxm_field
318
+ when InPort::OXM_FIELD
319
+ InPort
320
+ when EtherDestinationAddress::OXM_FIELD
321
+ masked? ? MaskedEtherDestinationAddress : EtherDestinationAddress
322
+ when EtherSourceAddress::OXM_FIELD
323
+ masked? ? MaskedEtherSourceAddress : EtherSourceAddress
324
+ when EtherType::OXM_FIELD
325
+ EtherType
326
+ when Ipv4SourceAddress::OXM_FIELD
327
+ masked? ? MaskedIpv4SourceAddress : Ipv4SourceAddress
328
+ when Ipv4DestinationAddress::OXM_FIELD
329
+ masked? ? MaskedIpv4DestinationAddress : Ipv4DestinationAddress
330
+ when IpProtocol::OXM_FIELD
331
+ IpProtocol
332
+ when TcpSourcePort::OXM_FIELD
333
+ TcpSourcePort
334
+ when TcpDestinationPort::OXM_FIELD
335
+ TcpDestinationPort
336
+ when UdpSourcePort::OXM_FIELD
337
+ UdpSourcePort
338
+ when UdpDestinationPort::OXM_FIELD
339
+ UdpDestinationPort
340
+ when Ipv6SourceAddress::OXM_FIELD
341
+ masked? ? MaskedIpv6SourceAddress : Ipv6SourceAddress
342
+ when Ipv6DestinationAddress::OXM_FIELD
343
+ masked? ? MaskedIpv6DestinationAddress : Ipv6DestinationAddress
344
+ else
345
+ fail "Unknown OXM field value: #{oxm_field}"
346
+ end
347
+ end
348
+ # rubocop:enable MethodLength
349
+ # rubocop:enable CyclomaticComplexity
350
+ # rubocop:enable PerceivedComplexity
351
+ # rubocop:enable AbcSize
352
+ end
353
+
354
+ endian :big
355
+
356
+ uint16 :match_type, value: MATCH_TYPE_OXM
357
+ uint16 :match_length, initial_value: -> { 4 + tlv_total_length }
358
+ array(:match_fields,
359
+ type: :match_field,
360
+ read_until: -> { tlv_length_left <= 5 },
361
+ onlyif: -> { match_length > 4 })
362
+ string :padding, length: :padding_length
363
+ hide :padding
364
+
365
+ def method_missing(method, *args, &block)
366
+ match_fields.each do |each|
367
+ next unless each.tlv_value.respond_to?(method)
368
+ return each.tlv_value.__send__(method, *args, &block)
369
+ end
370
+ fail NoMethodError, method.to_s
371
+ end
372
+
373
+ private
374
+
375
+ def tlv_length_left
376
+ match_length - tlv_total_length
377
+ end
378
+
379
+ def tlv_total_length
380
+ if match_fields.size > 0
381
+ match_fields.map(&:length).inject(&:+)
382
+ else
383
+ 0
384
+ end
385
+ end
386
+
387
+ def padding_length
388
+ (match_length + 7) / 8 * 8 - match_length
389
+ end
390
+ end
391
+
392
+ # Match.new option parser.
393
+ class Options
394
+ # rubocop:disable MethodLength
395
+ # rubocop:disable AbcSize
396
+ def initialize(user_attrs)
397
+ @match_fields = []
398
+
399
+ [:in_port, :ether_type, :ip_protocol,
400
+ :tcp_source_port, :tcp_destination_port,
401
+ :udp_source_port, :udp_destination_port].each do |each|
402
+ next unless user_attrs.key?(each)
403
+ klass = Match.const_get(each.to_s.split('_').map(&:capitalize).join)
404
+ @match_fields << { oxm_field: klass.const_get(:OXM_FIELD),
405
+ tlv_value: { each => user_attrs.fetch(each) } }
406
+ end
407
+
408
+ [:ether_destination_address, :ether_source_address,
409
+ :ipv4_source_address, :ipv4_destination_address,
410
+ :ipv6_source_address, :ipv6_destination_address].each do |each|
411
+ next unless user_attrs.key?(each)
412
+ klass = Match.const_get(each.to_s.split('_').map(&:capitalize).join)
413
+ mask_key = "#{each}_mask".to_sym
414
+ @match_fields <<
415
+ { oxm_field: klass.const_get(:OXM_FIELD),
416
+ oxm_hasmask: user_attrs.key?(mask_key) ? 1 : 0,
417
+ tlv_value: { each => user_attrs[each],
418
+ mask_key => user_attrs[mask_key] } }
419
+ end
420
+ end
421
+ # rubocop:enable MethodLength
422
+ # rubocop:enable AbcSize
423
+
424
+ def to_hash
425
+ { match_fields: @match_fields }
426
+ end
427
+ end
428
+
429
+ def self.read(raw_data)
430
+ allocate.tap do |message|
431
+ message.instance_variable_set(:@format, Format.read(raw_data))
432
+ end
433
+ end
434
+
435
+ def initialize(user_attrs = {})
436
+ @format = if user_attrs.empty?
437
+ Format.new
438
+ else
439
+ Format.new(Options.new(user_attrs).to_hash)
440
+ end
441
+ end
442
+
443
+ def length
444
+ @format.to_binary_s.length
445
+ end
446
+
447
+ def method_missing(method, *args, &block)
448
+ @format.__send__ method, *args, &block
449
+ end
450
+ end
451
+ end
452
+ end
@@ -10,3 +10,10 @@ require 'pio/open_flow13/echo'
10
10
  require 'pio/open_flow13/features_reply'
11
11
  require 'pio/open_flow13/features_request'
12
12
  require 'pio/open_flow13/hello'
13
+ require 'pio/open_flow13/match'
14
+
15
+ # Base module.
16
+ module Pio
17
+ remove_const :Match
18
+ Match = OpenFlow13::Match
19
+ end
@@ -0,0 +1,21 @@
1
+ require 'bindata'
2
+ require 'ipaddr'
3
+
4
+ module Pio
5
+ module Type
6
+ # IPv6 address
7
+ class Ipv6Address < BinData::Primitive
8
+ endian :big
9
+
10
+ uint128 :ipv6_address
11
+
12
+ def set(value)
13
+ self.ipv6_address = IPAddr.new(value, Socket::Constants::AF_INET6)
14
+ end
15
+
16
+ def get
17
+ IPAddr.new(ipv6_address, Socket::Constants::AF_INET6).to_s
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/pio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Base module.
2
2
  module Pio
3
3
  # gem version.
4
- VERSION = '0.20.0'.freeze
4
+ VERSION = '0.20.1'.freeze
5
5
  end
data/pio.gemspec CHANGED
@@ -31,33 +31,33 @@ Gem::Specification.new do |gem|
31
31
  gem.add_dependency 'bindata', '~> 2.1.0'
32
32
 
33
33
  gem.add_development_dependency 'rake'
34
- gem.add_development_dependency 'bundler', '~> 1.9.4'
34
+ gem.add_development_dependency 'bundler', '~> 1.10.3'
35
35
  gem.add_development_dependency 'pry', '~> 0.10.1'
36
36
 
37
37
  # Guard
38
- gem.add_development_dependency 'guard', '~> 2.12.5'
38
+ gem.add_development_dependency 'guard', '~> 2.12.6'
39
39
  gem.add_development_dependency 'guard-bundler', '~> 2.1.0'
40
40
  gem.add_development_dependency 'guard-cucumber', '~> 1.6.0'
41
- gem.add_development_dependency 'guard-rspec', '~> 4.5.0'
41
+ gem.add_development_dependency 'guard-rspec', '~> 4.5.2'
42
42
  gem.add_development_dependency 'guard-rubocop', '~> 1.2.0'
43
43
  gem.add_development_dependency 'rb-fchange', '~> 0.0.6'
44
- gem.add_development_dependency 'rb-fsevent', '~> 0.9.4'
44
+ gem.add_development_dependency 'rb-fsevent', '~> 0.9.5'
45
45
  gem.add_development_dependency 'rb-inotify', '~> 0.9.5'
46
46
  gem.add_development_dependency 'terminal-notifier-guard', '~> 1.6.4'
47
47
 
48
48
  # Docs
49
- gem.add_development_dependency 'inch', '~> 0.5.10'
49
+ gem.add_development_dependency 'inch', '~> 0.6.2'
50
50
  gem.add_development_dependency 'relish', '~> 0.7.1'
51
51
  gem.add_development_dependency 'yard', '~> 0.8.7.6'
52
52
 
53
53
  # Test
54
54
  gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.7'
55
- gem.add_development_dependency 'coveralls', '~> 0.8.0'
55
+ gem.add_development_dependency 'coveralls', '~> 0.8.1'
56
56
  gem.add_development_dependency 'cucumber', '~> 2.0.0'
57
57
  gem.add_development_dependency 'flay', '~> 2.6.1'
58
58
  gem.add_development_dependency 'flog', '~> 4.3.2'
59
- gem.add_development_dependency 'reek', '~> 2.1.0'
59
+ gem.add_development_dependency 'reek', '~> 2.2.1'
60
60
  gem.add_development_dependency 'rspec', '~> 3.2.0'
61
61
  gem.add_development_dependency 'rspec-given', '~> 3.7.0'
62
- gem.add_development_dependency 'rubocop', '~> 0.30.0'
62
+ gem.add_development_dependency 'rubocop', '~> 0.32.0'
63
63
  end
data/spec/pio/mac_spec.rb CHANGED
@@ -142,9 +142,9 @@ describe Pio::Mac do
142
142
  context 'with reserved address' do
143
143
  (0x0..0xf).each do |each|
144
144
  octet = format('%02x', each)
145
- reserved_address = "01:80:c2:00:00:#{ octet }"
145
+ reserved_address = "01:80:c2:00:00:#{octet}"
146
146
 
147
- context "when #{ reserved_address }" do
147
+ context "when #{reserved_address}" do
148
148
  let(:value) { reserved_address }
149
149
 
150
150
  describe '#reserved?' do