pio 0.21.1 → 0.22.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +1 -0
- data/Rakefile +1 -1
- data/features/open_flow13/match.feature +84 -0
- data/features/open_flow13/oxm_icmpv4_code_field.raw +0 -0
- data/features/open_flow13/oxm_icmpv4_type_field.raw +0 -0
- data/features/open_flow13/oxm_sctp_destination_field.raw +0 -0
- data/features/open_flow13/oxm_sctp_source_field.raw +0 -0
- data/features/open_flow13/packet_in.feature +80 -0
- data/features/open_flow13/packet_in.raw +0 -0
- data/features/open_flow13/packet_out.raw +0 -0
- data/lib/pio/open_flow10/exact_match.rb +2 -1
- data/lib/pio/open_flow10/packet_in.rb +2 -44
- data/lib/pio/open_flow13.rb +4 -3
- data/lib/pio/open_flow13/match.rb +66 -1
- data/lib/pio/open_flow13/packet_in.rb +87 -0
- data/lib/pio/parser.rb +44 -0
- data/lib/pio/version.rb +1 -1
- data/pio.gemspec +5 -5
- data/spec/pio/open_flow13/match_spec.rb +112 -0
- metadata +28 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06006d882906e150385cbe2e7932eb0d741277ee
|
4
|
+
data.tar.gz: 8b4f1fefee8d39a6e1ce9d173ace7284d5535d9f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e70773ffec96c1647cccc8b2a93b262f9655e3c3294e1ca6ee911385279a2fdb293357402eb5abb7f25e462785499b775cb82424fa4bb32859f71a257273aaf
|
7
|
+
data.tar.gz: d3c9c2353d742e752924726a77f9f91ab24c1dfdfe5870b651409c1b990eb75723ace6a39289316032571407a4edaca75c8ecfe6bd38ce3cb6c5e6b1f8833af1
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,15 @@
|
|
3
3
|
## develop (unreleased)
|
4
4
|
|
5
5
|
|
6
|
+
## 0.22.0 (6/25/2015)
|
7
|
+
### New features
|
8
|
+
* [#177](https://github.com/trema/pio/pull/177): Add new class `Pio::PacketIn` (OpenFlow1.3).
|
9
|
+
* [#173](https://github.com/trema/pio/pull/173): Add new classes `Pio::Match::VlanVid`, `Pio::Match::VlanPcp`.
|
10
|
+
* [#174](https://github.com/trema/pio/pull/174): Add new classes `Pio::Match::IpDscp`, `Pio::Match::IpEcn`.
|
11
|
+
* [#178](https://github.com/trema/pio/pull/178): Add new classes `Pio::Match::SctpSourcePort`, `Pio::Match::SctpDestinationPort`.
|
12
|
+
* [#180](https://github.com/trema/pio/pull/180): Add new classes `Pio::Match::Icmpv4Type`, `Pio::Match::Icmpv4Code`.
|
13
|
+
|
14
|
+
|
6
15
|
## 0.21.1 (6/24/2015)
|
7
16
|
### Bugs fixed
|
8
17
|
* [#179](https://github.com/trema/pio/pull/179): Fix wrong OXM length.
|
data/README.md
CHANGED
@@ -35,6 +35,7 @@ supports the following packet formats:
|
|
35
35
|
- [Echo Reply](https://relishapp.com/trema/pio/docs/open-flow13/pio-echo-reply)
|
36
36
|
- [Features Request](https://relishapp.com/trema/pio/docs/open-flow13/pio-features-request)
|
37
37
|
- [Features Reply](https://relishapp.com/trema/pio/docs/open-flow13/pio-features-reply)
|
38
|
+
- [Packet In](https://relishapp.com/trema/pio/docs/open-flow13/pio-packetin)
|
38
39
|
- [Flow Mod](https://relishapp.com/trema/pio/docs/open-flow13/pio-flowmod)
|
39
40
|
|
40
41
|
## Features Overview
|
data/Rakefile
CHANGED
@@ -232,6 +232,54 @@ Feature: Pio::Match
|
|
232
232
|
| ip_protocol | 17 |
|
233
233
|
| udp_destination_port | 3333 |
|
234
234
|
|
235
|
+
Scenario: new(ether_type: 0x0800, ip_protocol: 132, sctp_source_port: 22)
|
236
|
+
When I try to create an OpenFlow message with:
|
237
|
+
"""
|
238
|
+
Pio::Match.new(ether_type: 0x0800, ip_protocol: 132, sctp_source_port: 22)
|
239
|
+
"""
|
240
|
+
Then it should finish successfully
|
241
|
+
And the message have the following fields and values:
|
242
|
+
| field | value |
|
243
|
+
| ether_type | 2048 |
|
244
|
+
| ip_protocol | 132 |
|
245
|
+
| sctp_source_port | 22 |
|
246
|
+
|
247
|
+
Scenario: new(ether_type: 0x0800, ip_protocol: 132, sctp_destination_port: 22)
|
248
|
+
When I try to create an OpenFlow message with:
|
249
|
+
"""
|
250
|
+
Pio::Match.new(ether_type: 0x0800, ip_protocol: 132, sctp_destination_port: 22)
|
251
|
+
"""
|
252
|
+
Then it should finish successfully
|
253
|
+
And the message have the following fields and values:
|
254
|
+
| field | value |
|
255
|
+
| ether_type | 2048 |
|
256
|
+
| ip_protocol | 132 |
|
257
|
+
| sctp_destination_port | 22 |
|
258
|
+
|
259
|
+
Scenario: new(ether_type: 0x0800, ip_protocol: 1, icmpv4_type: 8)
|
260
|
+
When I try to create an OpenFlow message with:
|
261
|
+
"""
|
262
|
+
Pio::Match.new(ether_type: 0x0800, ip_protocol: 1, icmpv4_type: 8)
|
263
|
+
"""
|
264
|
+
Then it should finish successfully
|
265
|
+
And the message have the following fields and values:
|
266
|
+
| field | value |
|
267
|
+
| ether_type | 2048 |
|
268
|
+
| ip_protocol | 1 |
|
269
|
+
| icmpv4_type | 8 |
|
270
|
+
|
271
|
+
Scenario: new(ether_type: 0x0800, ip_protocol: 1, icmpv4_code: 0)
|
272
|
+
When I try to create an OpenFlow message with:
|
273
|
+
"""
|
274
|
+
Pio::Match.new(ether_type: 0x0800, ip_protocol: 1, icmpv4_code: 0)
|
275
|
+
"""
|
276
|
+
Then it should finish successfully
|
277
|
+
And the message have the following fields and values:
|
278
|
+
| field | value |
|
279
|
+
| ether_type | 2048 |
|
280
|
+
| ip_protocol | 1 |
|
281
|
+
| icmpv4_code | 0 |
|
282
|
+
|
235
283
|
Scenario: new(ether_type: 0x86dd, ipv6_source_address: '2001:db8:bd05:1d2:288a:1fc0:1:10ee')
|
236
284
|
When I try to create an OpenFlow message with:
|
237
285
|
"""
|
@@ -445,6 +493,42 @@ Feature: Pio::Match
|
|
445
493
|
| ip_protocol | 17 |
|
446
494
|
| udp_destination_port | 3333 |
|
447
495
|
|
496
|
+
Scenario: read (file: open_flow13/oxm_sctp_source_field.raw)
|
497
|
+
When I try to parse a file named "open_flow13/oxm_sctp_source_field.raw" with "Pio::Match" class
|
498
|
+
Then it should finish successfully
|
499
|
+
And the message have the following fields and values:
|
500
|
+
| field | value |
|
501
|
+
| ether_type | 2048 |
|
502
|
+
| ip_protocol | 132 |
|
503
|
+
| sctp_source_port | 22 |
|
504
|
+
|
505
|
+
Scenario: read (file: open_flow13/oxm_sctp_destination_field.raw)
|
506
|
+
When I try to parse a file named "open_flow13/oxm_sctp_destination_field.raw" with "Pio::Match" class
|
507
|
+
Then it should finish successfully
|
508
|
+
And the message have the following fields and values:
|
509
|
+
| field | value |
|
510
|
+
| ether_type | 2048 |
|
511
|
+
| ip_protocol | 132 |
|
512
|
+
| sctp_destination_port | 22 |
|
513
|
+
|
514
|
+
Scenario: read (file: open_flow13/oxm_icmpv4_type_field.raw)
|
515
|
+
When I try to parse a file named "open_flow13/oxm_icmpv4_type_field.raw" with "Pio::Match" class
|
516
|
+
Then it should finish successfully
|
517
|
+
And the message have the following fields and values:
|
518
|
+
| field | value |
|
519
|
+
| ether_type | 2048 |
|
520
|
+
| ip_protocol | 1 |
|
521
|
+
| icmpv4_type | 8 |
|
522
|
+
|
523
|
+
Scenario: read (file: open_flow13/oxm_icmpv4_code_field.raw)
|
524
|
+
When I try to parse a file named "open_flow13/oxm_icmpv4_code_field.raw" with "Pio::Match" class
|
525
|
+
Then it should finish successfully
|
526
|
+
And the message have the following fields and values:
|
527
|
+
| field | value |
|
528
|
+
| ether_type | 2048 |
|
529
|
+
| ip_protocol | 1 |
|
530
|
+
| icmpv4_code | 0 |
|
531
|
+
|
448
532
|
Scenario: read (file: open_flow13/oxm_ipv6_source_field.raw)
|
449
533
|
When I try to parse a file named "open_flow13/oxm_ipv6_source_field.raw" with "Pio::Match" class
|
450
534
|
Then it should finish successfully
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,80 @@
|
|
1
|
+
Feature: Pio::PacketIn
|
2
|
+
Background:
|
3
|
+
Given I use OpenFlow 1.3
|
4
|
+
|
5
|
+
Scenario: new
|
6
|
+
When I try to create an OpenFlow message with:
|
7
|
+
"""
|
8
|
+
Pio::PacketIn.new
|
9
|
+
"""
|
10
|
+
Then it should finish successfully
|
11
|
+
And the message have the following fields and values:
|
12
|
+
| field | value |
|
13
|
+
| class | Pio::PacketIn |
|
14
|
+
| ofp_version | 4 |
|
15
|
+
| message_type | 10 |
|
16
|
+
| message_length | 34 |
|
17
|
+
| transaction_id | 0 |
|
18
|
+
| xid | 0 |
|
19
|
+
| buffer_id | 0 |
|
20
|
+
| total_len | 0 |
|
21
|
+
| reason | :no_match |
|
22
|
+
| table_id | 0 |
|
23
|
+
| cookie | 0 |
|
24
|
+
| match.match_fields.size | 0 |
|
25
|
+
| raw_data.length | 0 |
|
26
|
+
|
27
|
+
Scenario: new (raw_data = ARP request)
|
28
|
+
When I try to create an OpenFlow message with:
|
29
|
+
"""
|
30
|
+
data_dump = [
|
31
|
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xac, 0x5d, 0x10, 0x31, 0x37,
|
32
|
+
0x79, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01,
|
33
|
+
0xac, 0x5d, 0x10, 0x31, 0x37, 0x79, 0xc0, 0xa8, 0x02, 0xfe, 0xff,
|
34
|
+
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xa8, 0x02, 0x05, 0x00, 0x00,
|
35
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
36
|
+
0x00, 0x00, 0x00, 0x00, 0x00
|
37
|
+
].pack('C*')
|
38
|
+
|
39
|
+
Pio::PacketIn.new(raw_data: data_dump)
|
40
|
+
"""
|
41
|
+
Then it should finish successfully
|
42
|
+
And the message have the following fields and values:
|
43
|
+
| field | value |
|
44
|
+
| class | Pio::PacketIn |
|
45
|
+
| ofp_version | 4 |
|
46
|
+
| message_type | 10 |
|
47
|
+
| message_length | 94 |
|
48
|
+
| transaction_id | 0 |
|
49
|
+
| xid | 0 |
|
50
|
+
| buffer_id | 0 |
|
51
|
+
| total_len | 60 |
|
52
|
+
| reason | :no_match |
|
53
|
+
| table_id | 0 |
|
54
|
+
| cookie | 0 |
|
55
|
+
| match.match_fields.size | 0 |
|
56
|
+
| raw_data.length | 60 |
|
57
|
+
| source_mac | ac:5d:10:31:37:79 |
|
58
|
+
| destination_mac | ff:ff:ff:ff:ff:ff |
|
59
|
+
|
60
|
+
Scenario: read
|
61
|
+
When I try to parse a file named "open_flow13/packet_in.raw" with "PacketIn" class
|
62
|
+
Then it should finish successfully
|
63
|
+
And the message have the following fields and values:
|
64
|
+
| field | value |
|
65
|
+
| class | Pio::PacketIn |
|
66
|
+
| ofp_version | 4 |
|
67
|
+
| message_type | 10 |
|
68
|
+
| message_length | 102 |
|
69
|
+
| transaction_id | 123 |
|
70
|
+
| xid | 123 |
|
71
|
+
| buffer_id.to_hex | 0xcafebabe |
|
72
|
+
| total_len | 60 |
|
73
|
+
| reason | :no_match |
|
74
|
+
| table_id | 0 |
|
75
|
+
| cookie | 0 |
|
76
|
+
| match.match_fields.size | 1 |
|
77
|
+
| match.match_fields[0].in_port | 1 |
|
78
|
+
| raw_data.length | 60 |
|
79
|
+
| source_mac | ac:5d:10:31:37:79 |
|
80
|
+
| destination_mac | ff:ff:ff:ff:ff:ff |
|
Binary file
|
Binary file
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'pio/open_flow10/match'
|
2
|
+
require 'pio/parser'
|
2
3
|
|
3
4
|
module Pio
|
4
5
|
# OpenFlow 1.0 exact match
|
@@ -8,7 +9,7 @@ module Pio
|
|
8
9
|
def initialize(packet_in)
|
9
10
|
data = packet_in.data
|
10
11
|
case data
|
11
|
-
when
|
12
|
+
when Pio::Parser::IPv4Packet
|
12
13
|
options = {
|
13
14
|
in_port: packet_in.in_port,
|
14
15
|
ether_source_address: packet_in.source_mac,
|
@@ -3,6 +3,7 @@ require 'pio/ethernet_header'
|
|
3
3
|
require 'pio/ipv4_header'
|
4
4
|
require 'pio/open_flow'
|
5
5
|
require 'pio/parse_error'
|
6
|
+
require 'pio/parser'
|
6
7
|
|
7
8
|
# Base module.
|
8
9
|
module Pio
|
@@ -44,49 +45,6 @@ module Pio
|
|
44
45
|
10 + raw_data.length
|
45
46
|
end
|
46
47
|
end
|
47
|
-
|
48
|
-
# Pio::PacketIn#raw_data parser
|
49
|
-
class DataParser
|
50
|
-
# Ethernet header parser
|
51
|
-
class EtherTypeParser < BinData::Record
|
52
|
-
endian :big
|
53
|
-
|
54
|
-
mac_address :destination_mac
|
55
|
-
mac_address :source_mac
|
56
|
-
uint16 :ether_type
|
57
|
-
end
|
58
|
-
|
59
|
-
# IPv4 packet parser
|
60
|
-
class IPv4Packet < BinData::Record
|
61
|
-
include EthernetHeader
|
62
|
-
include IPv4Header
|
63
|
-
|
64
|
-
endian :big
|
65
|
-
|
66
|
-
ethernet_header ether_type: EtherType::IPV4
|
67
|
-
ipv4_header
|
68
|
-
|
69
|
-
uint16 :transport_source_port
|
70
|
-
uint16 :transport_destination_port
|
71
|
-
rest :rest
|
72
|
-
end
|
73
|
-
|
74
|
-
# rubocop:disable MethodLength
|
75
|
-
def self.read(raw_data)
|
76
|
-
ethernet_header = EtherTypeParser.read(raw_data)
|
77
|
-
case ethernet_header.ether_type
|
78
|
-
when EthernetHeader::EtherType::IPV4, EthernetHeader::EtherType::VLAN
|
79
|
-
IPv4Packet.read raw_data
|
80
|
-
when EthernetHeader::EtherType::ARP
|
81
|
-
Pio::Arp.read raw_data
|
82
|
-
when EthernetHeader::EtherType::LLDP
|
83
|
-
Pio::Lldp.read raw_data
|
84
|
-
else
|
85
|
-
fail 'Failed to parse packet_in data.'
|
86
|
-
end
|
87
|
-
end
|
88
|
-
# rubocop:enable MethodLength
|
89
|
-
end
|
90
48
|
end
|
91
49
|
|
92
50
|
OpenFlow::Message.factory(PacketIn, OpenFlow::PACKET_IN) do
|
@@ -101,7 +59,7 @@ module Pio
|
|
101
59
|
alias_method :dpid=, :datapath_id=
|
102
60
|
|
103
61
|
def data
|
104
|
-
@data ||=
|
62
|
+
@data ||= Pio::Parser.read(raw_data)
|
105
63
|
end
|
106
64
|
|
107
65
|
def lldp?
|
data/lib/pio/open_flow13.rb
CHANGED
@@ -7,16 +7,17 @@ module Pio
|
|
7
7
|
end
|
8
8
|
|
9
9
|
require 'pio/open_flow13/apply'
|
10
|
-
require 'pio/open_flow13/goto_table'
|
11
|
-
require 'pio/open_flow13/write_metadata'
|
12
|
-
require 'pio/open_flow13/meter'
|
13
10
|
require 'pio/open_flow13/echo'
|
14
11
|
require 'pio/open_flow13/features_reply'
|
15
12
|
require 'pio/open_flow13/features_request'
|
16
13
|
require 'pio/open_flow13/flow_mod'
|
14
|
+
require 'pio/open_flow13/goto_table'
|
17
15
|
require 'pio/open_flow13/hello'
|
18
16
|
require 'pio/open_flow13/match'
|
17
|
+
require 'pio/open_flow13/meter'
|
18
|
+
require 'pio/open_flow13/packet_in'
|
19
19
|
require 'pio/open_flow13/send_out_port'
|
20
|
+
require 'pio/open_flow13/write_metadata'
|
20
21
|
|
21
22
|
# Base module.
|
22
23
|
module Pio
|
@@ -296,6 +296,58 @@ module Pio
|
|
296
296
|
end
|
297
297
|
end
|
298
298
|
|
299
|
+
# The value of OXM_OF_SCTP_SRC
|
300
|
+
class SctpSourcePort < BinData::Record
|
301
|
+
OXM_FIELD = 17
|
302
|
+
|
303
|
+
endian :big
|
304
|
+
|
305
|
+
uint16 :sctp_source_port
|
306
|
+
|
307
|
+
def length
|
308
|
+
2
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# The value of OXM_OF_SCTP_DST
|
313
|
+
class SctpDestinationPort < BinData::Record
|
314
|
+
OXM_FIELD = 18
|
315
|
+
|
316
|
+
endian :big
|
317
|
+
|
318
|
+
uint16 :sctp_destination_port
|
319
|
+
|
320
|
+
def length
|
321
|
+
2
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# The value of OXM_OF_ICMPV4_TYPE
|
326
|
+
class Icmpv4Type < BinData::Record
|
327
|
+
OXM_FIELD = 19
|
328
|
+
|
329
|
+
endian :big
|
330
|
+
|
331
|
+
uint8 :icmpv4_type
|
332
|
+
|
333
|
+
def length
|
334
|
+
1
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# The value of OXM_OF_ICMPV4_CODE
|
339
|
+
class Icmpv4Code < BinData::Record
|
340
|
+
OXM_FIELD = 20
|
341
|
+
|
342
|
+
endian :big
|
343
|
+
|
344
|
+
uint8 :icmpv4_code
|
345
|
+
|
346
|
+
def length
|
347
|
+
1
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
299
351
|
# The value of OXM_OF_IPV6_SRC
|
300
352
|
class Ipv6SourceAddress < BinData::Record
|
301
353
|
OXM_FIELD = 26
|
@@ -384,6 +436,10 @@ module Pio
|
|
384
436
|
tcp_destination_port TcpDestinationPort
|
385
437
|
udp_source_port UdpSourcePort
|
386
438
|
udp_destination_port UdpDestinationPort
|
439
|
+
sctp_source_port SctpSourcePort
|
440
|
+
sctp_destination_port SctpDestinationPort
|
441
|
+
icmpv4_type Icmpv4Type
|
442
|
+
icmpv4_code Icmpv4Code
|
387
443
|
ipv6_source_address Ipv6SourceAddress
|
388
444
|
masked_ipv6_source_address MaskedIpv6SourceAddress
|
389
445
|
ipv6_destination_address Ipv6DestinationAddress
|
@@ -442,6 +498,14 @@ module Pio
|
|
442
498
|
UdpSourcePort
|
443
499
|
when UdpDestinationPort::OXM_FIELD
|
444
500
|
UdpDestinationPort
|
501
|
+
when SctpSourcePort::OXM_FIELD
|
502
|
+
SctpSourcePort
|
503
|
+
when SctpDestinationPort::OXM_FIELD
|
504
|
+
SctpDestinationPort
|
505
|
+
when Icmpv4Type::OXM_FIELD
|
506
|
+
Icmpv4Type
|
507
|
+
when Icmpv4Code::OXM_FIELD
|
508
|
+
Icmpv4Code
|
445
509
|
when Ipv6SourceAddress::OXM_FIELD
|
446
510
|
masked? ? MaskedIpv6SourceAddress : Ipv6SourceAddress
|
447
511
|
when Ipv6DestinationAddress::OXM_FIELD
|
@@ -507,7 +571,8 @@ module Pio
|
|
507
571
|
|
508
572
|
[:in_port, :ether_type, :ip_protocol, :vlan_vid, :vlan_pcp,
|
509
573
|
:ip_dscp, :ip_ecn, :tcp_source_port, :tcp_destination_port,
|
510
|
-
:udp_source_port, :udp_destination_port
|
574
|
+
:udp_source_port, :udp_destination_port, :sctp_source_port,
|
575
|
+
:sctp_destination_port, :icmpv4_type, :icmpv4_code].each do |each|
|
511
576
|
next unless user_attrs.key?(each)
|
512
577
|
klass = Match.const_get(each.to_s.split('_').map(&:capitalize).join)
|
513
578
|
@match_fields << { oxm_field: klass.const_get(:OXM_FIELD),
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# Base module.
|
2
|
+
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
|
21
|
+
|
22
|
+
def set(value)
|
23
|
+
self.reason = REASONS.fetch(value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
endian :big
|
28
|
+
|
29
|
+
uint32 :buffer_id
|
30
|
+
uint16 :total_len, initial_value: -> { raw_data.length }
|
31
|
+
reason :reason
|
32
|
+
uint8 :table_id
|
33
|
+
uint64 :cookie
|
34
|
+
oxm :match
|
35
|
+
string :padding, length: 2
|
36
|
+
hide :padding
|
37
|
+
string :raw_data, read_length: :total_len
|
38
|
+
|
39
|
+
def length
|
40
|
+
16 + match.length + padding.length + raw_data.length
|
41
|
+
end
|
42
|
+
|
43
|
+
def data
|
44
|
+
@data ||= Pio::Parser.read(raw_data)
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_missing(method, *args)
|
48
|
+
data.__send__(method, *args).snapshot
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
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
|
65
|
+
|
66
|
+
def method_missing(method, *args, &block)
|
67
|
+
body.__send__ method, *args, &block
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.read(raw_data)
|
72
|
+
allocate.tap do |message|
|
73
|
+
message.instance_variable_set(:@format, Format.read(raw_data))
|
74
|
+
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
|
+
|
83
|
+
def method_missing(method, *args, &block)
|
84
|
+
@format.__send__ method, *args, &block
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/pio/parser.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Pio
|
2
|
+
# Raw data parser.
|
3
|
+
class Parser
|
4
|
+
# Ethernet header parser
|
5
|
+
class EtherTypeParser < BinData::Record
|
6
|
+
endian :big
|
7
|
+
|
8
|
+
mac_address :destination_mac
|
9
|
+
mac_address :source_mac
|
10
|
+
uint16 :ether_type
|
11
|
+
end
|
12
|
+
|
13
|
+
# IPv4 packet parser
|
14
|
+
class IPv4Packet < BinData::Record
|
15
|
+
include EthernetHeader
|
16
|
+
include IPv4Header
|
17
|
+
|
18
|
+
endian :big
|
19
|
+
|
20
|
+
ethernet_header ether_type: EtherType::IPV4
|
21
|
+
ipv4_header
|
22
|
+
|
23
|
+
uint16 :transport_source_port
|
24
|
+
uint16 :transport_destination_port
|
25
|
+
rest :rest
|
26
|
+
end
|
27
|
+
|
28
|
+
# rubocop:disable MethodLength
|
29
|
+
def self.read(raw_data)
|
30
|
+
ethernet_header = EtherTypeParser.read(raw_data)
|
31
|
+
case ethernet_header.ether_type
|
32
|
+
when EthernetHeader::EtherType::IPV4, EthernetHeader::EtherType::VLAN
|
33
|
+
IPv4Packet.read raw_data
|
34
|
+
when EthernetHeader::EtherType::ARP
|
35
|
+
Pio::Arp.read raw_data
|
36
|
+
when EthernetHeader::EtherType::LLDP
|
37
|
+
Pio::Lldp.read raw_data
|
38
|
+
else
|
39
|
+
fail 'Failed to parse packet_in data.'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
# rubocop:enable MethodLength
|
43
|
+
end
|
44
|
+
end
|
data/lib/pio/version.rb
CHANGED
data/pio.gemspec
CHANGED
@@ -31,7 +31,7 @@ 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.10.
|
34
|
+
gem.add_development_dependency 'bundler', '~> 1.10.5'
|
35
35
|
gem.add_development_dependency 'pry', '~> 0.10.1'
|
36
36
|
|
37
37
|
# Guard
|
@@ -46,18 +46,18 @@ Gem::Specification.new do |gem|
|
|
46
46
|
gem.add_development_dependency 'terminal-notifier-guard', '~> 1.6.4'
|
47
47
|
|
48
48
|
# Docs
|
49
|
-
gem.add_development_dependency 'inch', '~> 0.6.
|
49
|
+
gem.add_development_dependency 'inch', '~> 0.6.3'
|
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.
|
55
|
+
gem.add_development_dependency 'coveralls', '~> 0.8.2'
|
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
59
|
gem.add_development_dependency 'reek', '~> 2.2.1'
|
60
|
-
gem.add_development_dependency 'rspec', '~> 3.
|
60
|
+
gem.add_development_dependency 'rspec', '~> 3.3.0'
|
61
61
|
gem.add_development_dependency 'rspec-given', '~> 3.7.0'
|
62
|
-
gem.add_development_dependency 'rubocop', '~> 0.32.
|
62
|
+
gem.add_development_dependency 'rubocop', '~> 0.32.1'
|
63
63
|
end
|
@@ -291,6 +291,118 @@ describe Pio::OpenFlow13::Match do
|
|
291
291
|
And { match.match_fields[1].masked? == false }
|
292
292
|
And { match.match_fields[1].oxm_length == 4 }
|
293
293
|
end
|
294
|
+
|
295
|
+
context 'with ether_type: 0x0800, ip_protocol: 132, sctp_source_port: 22' do
|
296
|
+
When(:match) do
|
297
|
+
Pio::OpenFlow13::Match.new(
|
298
|
+
ether_type: 0x0800,
|
299
|
+
ip_protocol: 132,
|
300
|
+
sctp_source_port: 22
|
301
|
+
)
|
302
|
+
end
|
303
|
+
Then { match.ether_type == 0x0800 }
|
304
|
+
Then { match.ip_protocol == 132 }
|
305
|
+
Then { match.sctp_source_port == 22 }
|
306
|
+
And { match.class == Pio::OpenFlow13::Match }
|
307
|
+
And { match.length == 24 }
|
308
|
+
And { match.match_type == Pio::OpenFlow13::MATCH_TYPE_OXM }
|
309
|
+
And { match.match_length == 21 }
|
310
|
+
And { match.match_fields.size == 3 }
|
311
|
+
And do
|
312
|
+
match.match_fields[2].oxm_class ==
|
313
|
+
Pio::OpenFlow13::Match::OXM_CLASS_OPENFLOW_BASIC
|
314
|
+
end
|
315
|
+
And do
|
316
|
+
match.match_fields[2].oxm_field ==
|
317
|
+
Pio::OpenFlow13::Match::SctpSourcePort::OXM_FIELD
|
318
|
+
end
|
319
|
+
And { match.match_fields[2].masked? == false }
|
320
|
+
And { match.match_fields[0].oxm_length == 2 }
|
321
|
+
end
|
322
|
+
|
323
|
+
context 'with ether_type: 0x0800, ip_protocol: 132, sctp_destination_port: 22' do
|
324
|
+
When(:match) do
|
325
|
+
Pio::OpenFlow13::Match.new(
|
326
|
+
ether_type: 0x0800,
|
327
|
+
ip_protocol: 132,
|
328
|
+
sctp_destination_port: 22
|
329
|
+
)
|
330
|
+
end
|
331
|
+
Then { match.ether_type == 0x0800 }
|
332
|
+
Then { match.ip_protocol == 132 }
|
333
|
+
Then { match.sctp_destination_port == 22 }
|
334
|
+
And { match.class == Pio::OpenFlow13::Match }
|
335
|
+
And { match.length == 24 }
|
336
|
+
And { match.match_type == Pio::OpenFlow13::MATCH_TYPE_OXM }
|
337
|
+
And { match.match_length == 21 }
|
338
|
+
And { match.match_fields.size == 3 }
|
339
|
+
And do
|
340
|
+
match.match_fields[2].oxm_class ==
|
341
|
+
Pio::OpenFlow13::Match::OXM_CLASS_OPENFLOW_BASIC
|
342
|
+
end
|
343
|
+
And do
|
344
|
+
match.match_fields[2].oxm_field ==
|
345
|
+
Pio::OpenFlow13::Match::SctpDestinationPort::OXM_FIELD
|
346
|
+
end
|
347
|
+
And { match.match_fields[2].masked? == false }
|
348
|
+
And { match.match_fields[0].oxm_length == 2 }
|
349
|
+
end
|
350
|
+
|
351
|
+
context 'with ether_type: 0x0800, ip_protocol: 1, icmpv4_type: 8' do
|
352
|
+
When(:match) do
|
353
|
+
Pio::OpenFlow13::Match.new(
|
354
|
+
ether_type: 0x0800,
|
355
|
+
ip_protocol: 1,
|
356
|
+
icmpv4_type: 8
|
357
|
+
)
|
358
|
+
end
|
359
|
+
Then { match.ether_type == 0x0800 }
|
360
|
+
Then { match.ip_protocol == 1 }
|
361
|
+
Then { match.icmpv4_type == 8 }
|
362
|
+
And { match.class == Pio::OpenFlow13::Match }
|
363
|
+
And { match.length == 24 }
|
364
|
+
And { match.match_type == Pio::OpenFlow13::MATCH_TYPE_OXM }
|
365
|
+
And { match.match_length == 20 }
|
366
|
+
And { match.match_fields.size == 3 }
|
367
|
+
And do
|
368
|
+
match.match_fields[2].oxm_class ==
|
369
|
+
Pio::OpenFlow13::Match::OXM_CLASS_OPENFLOW_BASIC
|
370
|
+
end
|
371
|
+
And do
|
372
|
+
match.match_fields[2].oxm_field ==
|
373
|
+
Pio::OpenFlow13::Match::Icmpv4Type::OXM_FIELD
|
374
|
+
end
|
375
|
+
And { match.match_fields[2].masked? == false }
|
376
|
+
And { match.match_fields[2].oxm_length == 1 }
|
377
|
+
end
|
378
|
+
|
379
|
+
context 'with ether_type: 0x0800, ip_protocol: 1, icmpv4_code: 0' do
|
380
|
+
When(:match) do
|
381
|
+
Pio::OpenFlow13::Match.new(
|
382
|
+
ether_type: 0x0800,
|
383
|
+
ip_protocol: 1,
|
384
|
+
icmpv4_code: 0
|
385
|
+
)
|
386
|
+
end
|
387
|
+
Then { match.ether_type == 0x0800 }
|
388
|
+
Then { match.ip_protocol == 1 }
|
389
|
+
Then { match.icmpv4_code == 0 }
|
390
|
+
And { match.class == Pio::OpenFlow13::Match }
|
391
|
+
And { match.length == 24 }
|
392
|
+
And { match.match_type == Pio::OpenFlow13::MATCH_TYPE_OXM }
|
393
|
+
And { match.match_length == 20 }
|
394
|
+
And { match.match_fields.size == 3 }
|
395
|
+
And do
|
396
|
+
match.match_fields[2].oxm_class ==
|
397
|
+
Pio::OpenFlow13::Match::OXM_CLASS_OPENFLOW_BASIC
|
398
|
+
end
|
399
|
+
And do
|
400
|
+
match.match_fields[2].oxm_field ==
|
401
|
+
Pio::OpenFlow13::Match::Icmpv4Code::OXM_FIELD
|
402
|
+
end
|
403
|
+
And { match.match_fields[2].masked? == false }
|
404
|
+
And { match.match_fields[2].oxm_length == 1 }
|
405
|
+
end
|
294
406
|
end
|
295
407
|
|
296
408
|
def read_raw_data_file(name)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yasuhito Takamiya
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bindata
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.10.
|
47
|
+
version: 1.10.5
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.10.
|
54
|
+
version: 1.10.5
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: pry
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,14 +198,14 @@ dependencies:
|
|
198
198
|
requirements:
|
199
199
|
- - ~>
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: 0.6.
|
201
|
+
version: 0.6.3
|
202
202
|
type: :development
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
206
|
- - ~>
|
207
207
|
- !ruby/object:Gem::Version
|
208
|
-
version: 0.6.
|
208
|
+
version: 0.6.3
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
210
|
name: relish
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,14 +254,14 @@ dependencies:
|
|
254
254
|
requirements:
|
255
255
|
- - ~>
|
256
256
|
- !ruby/object:Gem::Version
|
257
|
-
version: 0.8.
|
257
|
+
version: 0.8.2
|
258
258
|
type: :development
|
259
259
|
prerelease: false
|
260
260
|
version_requirements: !ruby/object:Gem::Requirement
|
261
261
|
requirements:
|
262
262
|
- - ~>
|
263
263
|
- !ruby/object:Gem::Version
|
264
|
-
version: 0.8.
|
264
|
+
version: 0.8.2
|
265
265
|
- !ruby/object:Gem::Dependency
|
266
266
|
name: cucumber
|
267
267
|
requirement: !ruby/object:Gem::Requirement
|
@@ -324,14 +324,14 @@ dependencies:
|
|
324
324
|
requirements:
|
325
325
|
- - ~>
|
326
326
|
- !ruby/object:Gem::Version
|
327
|
-
version: 3.
|
327
|
+
version: 3.3.0
|
328
328
|
type: :development
|
329
329
|
prerelease: false
|
330
330
|
version_requirements: !ruby/object:Gem::Requirement
|
331
331
|
requirements:
|
332
332
|
- - ~>
|
333
333
|
- !ruby/object:Gem::Version
|
334
|
-
version: 3.
|
334
|
+
version: 3.3.0
|
335
335
|
- !ruby/object:Gem::Dependency
|
336
336
|
name: rspec-given
|
337
337
|
requirement: !ruby/object:Gem::Requirement
|
@@ -352,14 +352,14 @@ dependencies:
|
|
352
352
|
requirements:
|
353
353
|
- - ~>
|
354
354
|
- !ruby/object:Gem::Version
|
355
|
-
version: 0.32.
|
355
|
+
version: 0.32.1
|
356
356
|
type: :development
|
357
357
|
prerelease: false
|
358
358
|
version_requirements: !ruby/object:Gem::Requirement
|
359
359
|
requirements:
|
360
360
|
- - ~>
|
361
361
|
- !ruby/object:Gem::Version
|
362
|
-
version: 0.32.
|
362
|
+
version: 0.32.1
|
363
363
|
description: Pure ruby packet parser and generator.
|
364
364
|
email:
|
365
365
|
- yasuhito@gmail.com
|
@@ -514,6 +514,8 @@ files:
|
|
514
514
|
- features/open_flow13/oxm_ether_destination_field.raw
|
515
515
|
- features/open_flow13/oxm_ether_source_field.raw
|
516
516
|
- features/open_flow13/oxm_ether_type_field.raw
|
517
|
+
- features/open_flow13/oxm_icmpv4_code_field.raw
|
518
|
+
- features/open_flow13/oxm_icmpv4_type_field.raw
|
517
519
|
- features/open_flow13/oxm_in_phy_port_field.raw
|
518
520
|
- features/open_flow13/oxm_in_port_field.raw
|
519
521
|
- features/open_flow13/oxm_ip_dscp_field.raw
|
@@ -531,6 +533,8 @@ files:
|
|
531
533
|
- features/open_flow13/oxm_metadata_field.raw
|
532
534
|
- features/open_flow13/oxm_metadata_masked_field.raw
|
533
535
|
- features/open_flow13/oxm_no_fields.raw
|
536
|
+
- features/open_flow13/oxm_sctp_destination_field.raw
|
537
|
+
- features/open_flow13/oxm_sctp_source_field.raw
|
534
538
|
- features/open_flow13/oxm_tcp_destination_field.raw
|
535
539
|
- features/open_flow13/oxm_tcp_field.raw
|
536
540
|
- features/open_flow13/oxm_tcp_source_field.raw
|
@@ -539,6 +543,9 @@ files:
|
|
539
543
|
- features/open_flow13/oxm_udp_source_field.raw
|
540
544
|
- features/open_flow13/oxm_vlan_pcp_field.raw
|
541
545
|
- features/open_flow13/oxm_vlan_vid_field.raw
|
546
|
+
- features/open_flow13/packet_in.feature
|
547
|
+
- features/open_flow13/packet_in.raw
|
548
|
+
- features/open_flow13/packet_out.raw
|
542
549
|
- features/open_flow13/send_out_port.feature
|
543
550
|
- features/open_flow13/send_out_port.raw
|
544
551
|
- features/open_flow13/write_metadata.feature
|
@@ -638,10 +645,12 @@ files:
|
|
638
645
|
- lib/pio/open_flow13/hello.rb
|
639
646
|
- lib/pio/open_flow13/match.rb
|
640
647
|
- lib/pio/open_flow13/meter.rb
|
648
|
+
- lib/pio/open_flow13/packet_in.rb
|
641
649
|
- lib/pio/open_flow13/send_out_port.rb
|
642
650
|
- lib/pio/open_flow13/write_metadata.rb
|
643
651
|
- lib/pio/options.rb
|
644
652
|
- lib/pio/parse_error.rb
|
653
|
+
- lib/pio/parser.rb
|
645
654
|
- lib/pio/payload.rb
|
646
655
|
- lib/pio/pcap.rb
|
647
656
|
- lib/pio/type/ip_address.rb
|
@@ -857,6 +866,8 @@ test_files:
|
|
857
866
|
- features/open_flow13/oxm_ether_destination_field.raw
|
858
867
|
- features/open_flow13/oxm_ether_source_field.raw
|
859
868
|
- features/open_flow13/oxm_ether_type_field.raw
|
869
|
+
- features/open_flow13/oxm_icmpv4_code_field.raw
|
870
|
+
- features/open_flow13/oxm_icmpv4_type_field.raw
|
860
871
|
- features/open_flow13/oxm_in_phy_port_field.raw
|
861
872
|
- features/open_flow13/oxm_in_port_field.raw
|
862
873
|
- features/open_flow13/oxm_ip_dscp_field.raw
|
@@ -874,6 +885,8 @@ test_files:
|
|
874
885
|
- features/open_flow13/oxm_metadata_field.raw
|
875
886
|
- features/open_flow13/oxm_metadata_masked_field.raw
|
876
887
|
- features/open_flow13/oxm_no_fields.raw
|
888
|
+
- features/open_flow13/oxm_sctp_destination_field.raw
|
889
|
+
- features/open_flow13/oxm_sctp_source_field.raw
|
877
890
|
- features/open_flow13/oxm_tcp_destination_field.raw
|
878
891
|
- features/open_flow13/oxm_tcp_field.raw
|
879
892
|
- features/open_flow13/oxm_tcp_source_field.raw
|
@@ -882,6 +895,9 @@ test_files:
|
|
882
895
|
- features/open_flow13/oxm_udp_source_field.raw
|
883
896
|
- features/open_flow13/oxm_vlan_pcp_field.raw
|
884
897
|
- features/open_flow13/oxm_vlan_vid_field.raw
|
898
|
+
- features/open_flow13/packet_in.feature
|
899
|
+
- features/open_flow13/packet_in.raw
|
900
|
+
- features/open_flow13/packet_out.raw
|
885
901
|
- features/open_flow13/send_out_port.feature
|
886
902
|
- features/open_flow13/send_out_port.raw
|
887
903
|
- features/open_flow13/write_metadata.feature
|