pio 0.20.0 → 0.20.1

Sign up to get free protection for your applications and to get access to all the features.
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