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