pio 0.1.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.
@@ -0,0 +1,22 @@
1
+ require "rubygems"
2
+ require "bindata"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ # TLV value field of system capabilities TLV
8
+ class SystemCapabilitiesValue < BinData::Record
9
+ endian :big
10
+
11
+ uint16be :system_capabilities
12
+ uint16be :enabled_capabilities
13
+ end
14
+ end
15
+ end
16
+
17
+
18
+ ### Local variables:
19
+ ### mode: Ruby
20
+ ### coding: utf-8-unix
21
+ ### indent-tabs-mode: nil
22
+ ### End:
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+ require "bindata"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ # TLV value field of system description TLV
8
+ class SystemDescriptionValue < BinData::Record
9
+ endian :big
10
+
11
+ stringz :system_description
12
+ end
13
+ end
14
+ end
15
+
16
+
17
+ ### Local variables:
18
+ ### mode: Ruby
19
+ ### coding: utf-8-unix
20
+ ### indent-tabs-mode: nil
21
+ ### End:
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+ require "bindata"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ # TLV value field of system name TLV
8
+ class SystemNameValue < BinData::Record
9
+ endian :big
10
+
11
+ stringz :system_name
12
+ end
13
+ end
14
+ end
15
+
16
+
17
+ ### Local variables:
18
+ ### mode: Ruby
19
+ ### coding: utf-8-unix
20
+ ### indent-tabs-mode: nil
21
+ ### End:
@@ -0,0 +1,33 @@
1
+ require "rubygems"
2
+ require "bindata"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ # Time to live TLV
8
+ class TtlTlv < BinData::Primitive
9
+ endian :big
10
+
11
+ bit7 :tlv_type, :value => 3
12
+ bit9 :tlv_info_length, :value => 2
13
+ string :ttl, :read_length => :tlv_info_length
14
+
15
+
16
+ def get
17
+ BinData::Int16be.read( ttl )
18
+ end
19
+
20
+
21
+ def set value
22
+ self.ttl = BinData::Int16be.new( value ).to_binary_s
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+ ### Local variables:
30
+ ### mode: Ruby
31
+ ### coding: utf-8-unix
32
+ ### indent-tabs-mode: nil
33
+ ### End:
@@ -0,0 +1,30 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ # Base module.
20
+ module Pio
21
+ # gem version.
22
+ VERSION = "0.1.0"
23
+ end
24
+
25
+
26
+ ### Local variables:
27
+ ### mode: Ruby
28
+ ### coding: utf-8
29
+ ### indent-tabs-mode: nil
30
+ ### End:
data/pio.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ lib = File.expand_path( "../lib", __FILE__ )
2
+ $LOAD_PATH.unshift( lib ) unless $LOAD_PATH.include?( lib )
3
+ require "pio/version"
4
+
5
+
6
+ Gem::Specification.new do | gem |
7
+ gem.name = "pio"
8
+ gem.version = Pio::VERSION
9
+ gem.summary = "Packet parser and generator."
10
+ gem.description = "Pure ruby packet parser and generator."
11
+
12
+ gem.license = "GPL3"
13
+
14
+ gem.authors = [ "Yasuhito Takamiya" ]
15
+ gem.email = [ "yasuhito@gmail.com" ]
16
+ gem.homepage = "http://github.com/trema/pio"
17
+
18
+ gem.files = `git ls-files`.split( "\n" )
19
+
20
+ gem.require_paths = [ "lib" ]
21
+
22
+ gem.extra_rdoc_files = [ "README.md" ]
23
+ gem.test_files = `git ls-files -- {spec,features}/*`.split( "\n" )
24
+ end
25
+
26
+
27
+ ### Local variables:
28
+ ### mode: Ruby
29
+ ### coding: utf-8-unix
30
+ ### indent-tabs-mode: nil
31
+ ### End:
@@ -0,0 +1,27 @@
1
+ require File.join( File.dirname( __FILE__ ), "..", "..", "spec_helper" )
2
+ require "pio/lldp/chassis-id-tlv"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ describe ChassisIdTlv do
8
+ subject { ChassisIdTlv.read( data.pack( "C*" ) ) }
9
+
10
+ context "parsing a raw data" do
11
+ let( :data ) { [ 0x02, 0x07, 0x04, 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d ] }
12
+
13
+ its( :tlv_type ) { should eq 1 }
14
+ its( :tlv_info_length ) { should eq 7 }
15
+ its( :subtype ) { should eq 4 }
16
+ its( :chassis_id ) { should eq data[ -6..-1 ].pack( "C*" ) }
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+
23
+ ### Local variables:
24
+ ### mode: Ruby
25
+ ### coding: utf-8-unix
26
+ ### indent-tabs-mode: nil
27
+ ### End:
@@ -0,0 +1,20 @@
1
+ require File.join( File.dirname( __FILE__ ), "..", "..", "spec_helper" )
2
+ require "pio/lldp/end-of-lldpdu-value"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ describe EndOfLldpduValue do
8
+ subject { EndOfLldpduValue.new }
9
+
10
+ its( :tlv_info_string ) { should be_empty }
11
+ end
12
+ end
13
+ end
14
+
15
+
16
+ ### Local variables:
17
+ ### mode: Ruby
18
+ ### coding: utf-8-unix
19
+ ### indent-tabs-mode: nil
20
+ ### End:
@@ -0,0 +1,82 @@
1
+ require File.join( File.dirname( __FILE__ ), "..", "..", "spec_helper" )
2
+ require "pio/lldp/frame"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ describe Frame do
8
+ it "should parse a minimal LLDP" do
9
+ sample_packet = [
10
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, # Destination MAC
11
+ 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d, # Source MAC
12
+ 0x88, 0xcc, # Ethertype
13
+ 0x02, 0x07, 0x04, 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d, # Chassis ID TLV
14
+ 0x04, 0x0d, 0x01, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x31, # Port ID TLV
15
+ 0x06, 0x02, 0x00, 0x78, # Time to live TLV
16
+ 0x00, 0x00, # End of LLDPDU TLV
17
+ ].pack( "C*" )
18
+
19
+ lldp = Frame.read( sample_packet )
20
+ end
21
+
22
+
23
+ it "should parse LLDP" do
24
+ sample_packet = [
25
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, # Destination MAC
26
+ 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d, # Source MAC
27
+ 0x88, 0xcc, # Ethertype
28
+ 0x02, 0x07, 0x04, 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d, # Chassis ID TLV
29
+ 0x04, 0x0d, 0x01, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x31, # Port ID TLV
30
+ 0x06, 0x02, 0x00, 0x78, # Time to live TLV
31
+ 0x08, 0x17, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x2d, 0x50, 0x6f, 0x72, 0x74, 0x20, 0x31, 0x30, 0x30, 0x31, 0x00, # Port Description
32
+ 0x0a, 0x0d, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x00, # System Name
33
+ 0x0c, 0x4c, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x20, 0x2d, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x34, 0x65, 0x2e, 0x31, 0x20, 0x28, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x35, 0x29, 0x20, 0x62, 0x79, 0x20, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x30, 0x35, 0x2f, 0x32, 0x37, 0x2f, 0x30, 0x35, 0x20, 0x30, 0x34, 0x3a, 0x35, 0x33, 0x3a, 0x31, 0x31, 0x00, # System Description
34
+ 0x0e, 0x04, 0x00, 0x14, 0x00, 0x14, # System Capabilities
35
+ 0x10, 0x0e, 0x07, 0x06, 0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0, 0x02, 0x00, 0x00, 0x03, 0xe9, 0x00, # Management Address
36
+ 0xfe, 0x07, 0x00, 0x12, 0x0f, 0x02, 0x07, 0x01, 0x00,
37
+ 0x00, 0x00, # End of LLDPDU TLV
38
+ ].pack( "C*" )
39
+
40
+ lldp = Frame.read( sample_packet )
41
+ lldp.optional_tlv[ 0 ][ :tlv_type ].should eq 4
42
+ lldp.optional_tlv[ 1 ][ :tlv_type ].should eq 5
43
+ lldp.optional_tlv[ 2 ][ :tlv_type ].should eq 6
44
+ lldp.optional_tlv[ 3 ][ :tlv_type ].should eq 7
45
+ lldp.optional_tlv[ 4 ][ :tlv_type ].should eq 8
46
+ lldp.optional_tlv[ 5 ][ :tlv_type ].should eq 0
47
+ end
48
+
49
+
50
+ it "should create a valid LLDP packet" do
51
+ # sample packet taken from http://www.cloudshark.org/captures/05a981251df9
52
+ sample_packet = [
53
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, # Destination MAC
54
+ 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d, # Source MAC
55
+ 0x88, 0xcc, # Ethertype
56
+ 0x02, 0x07, 0x04, 0x00, 0x19, 0x2f, 0xa7, 0xb2, 0x8d, # Chassis ID TLV
57
+ 0x04, 0x0d, 0x01, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x31, # Port ID TLV
58
+ 0x06, 0x02, 0x00, 0x78, # Time to live TLV
59
+ 0x00, 0x00 # End of LLDPDU TLV
60
+ ].pack( "C*" )
61
+
62
+ lldp_frame = Frame.new
63
+ lldp_frame.destination_mac = "01:80:c2:00:00:0e"
64
+ lldp_frame.source_mac = "00:19:2f:a7:b2:8d"
65
+ lldp_frame.chassis_id.subtype = 4
66
+ lldp_frame.chassis_id = "\x00\x19\x2f\xa7\xb2\x8d"
67
+ lldp_frame.port_id.subtype = 1
68
+ lldp_frame.port_id = "Uplink to S1"
69
+ lldp_frame.ttl = 120
70
+
71
+ ( lldp_frame.to_binary_s.unpack( "H*" )[ 0 ] + "0000" ).should == sample_packet.unpack( "H*" )[ 0 ]
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+
78
+ ### Local variables:
79
+ ### mode: Ruby
80
+ ### coding: utf-8-unix
81
+ ### indent-tabs-mode: nil
82
+ ### End:
@@ -0,0 +1,20 @@
1
+ require File.join( File.dirname( __FILE__ ), "..", "..", "spec_helper" )
2
+ require "pio/lldp/mac-address"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ describe MacAddress do
8
+ subject { MacAddress.new( "01:80:c2:00:00:0e" ) }
9
+
10
+ its( :to_binary_s ) { should eq "\001\200\302\000\000\016" }
11
+ end
12
+ end
13
+ end
14
+
15
+
16
+ ### Local variables:
17
+ ### mode: Ruby
18
+ ### coding: utf-8-unix
19
+ ### indent-tabs-mode: nil
20
+ ### End:
@@ -0,0 +1,81 @@
1
+ require File.join( File.dirname( __FILE__ ), "..", "..", "spec_helper" )
2
+ require "pio/lldp/optional-tlv"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ describe OptionalTlv do
8
+ subject { OptionalTlv.read( data ) }
9
+
10
+
11
+ context "when parsing End Of LLDPDU TLV" do
12
+ let( :data ) { [ 0x00, 0x00 ].pack( "C*" ) }
13
+
14
+ its( :tlv_type ) { should eq 0 }
15
+ its( :tlv_info_length ) { should eq 0 }
16
+ its( :tlv_value ) { should eq "tlv_info_string" => "" }
17
+ end
18
+
19
+
20
+ context "when parsing Port Description TLV" do
21
+ let( :data ) { [ 0x08, 0x17, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x2d, 0x50, 0x6f, 0x72, 0x74, 0x20, 0x31, 0x30, 0x30, 0x31, 0x00 ].pack( "C*" ) }
22
+
23
+ its( :tlv_type ) { should eq 4 }
24
+ its( :tlv_info_length ) { should eq 23 }
25
+ its( :tlv_value ) { should eq( { "port_description" => "Summit300-48-Port 1001" } ) }
26
+ end
27
+
28
+
29
+ context "when parsing System Name TLV" do
30
+ let( :data ) { [ 0x0a, 0x0d, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x00 ].pack( "C*" ) }
31
+
32
+ its( :tlv_type ) { should eq 5 }
33
+ its( :tlv_info_length ) { should eq 13 }
34
+ its( :tlv_value ) { should eq( { "system_name" => "Summit300-48" } ) }
35
+ end
36
+
37
+
38
+ context "when parsing System Description TLV" do
39
+ let( :data ) { [ 0x0c, 0x4c, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x20, 0x2d, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x34, 0x65, 0x2e, 0x31, 0x20, 0x28, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x35, 0x29, 0x20, 0x62, 0x79, 0x20, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x30, 0x35, 0x2f, 0x32, 0x37, 0x2f, 0x30, 0x35, 0x20, 0x30, 0x34, 0x3a, 0x35, 0x33, 0x3a, 0x31, 0x31, 0x00 ].pack( "C*" ) }
40
+
41
+ its( :tlv_type ) { should eq 6 }
42
+ its( :tlv_info_length ) { should eq 76 }
43
+ its( :tlv_value ) { should eq( { "system_description"=>"Summit300-48 - Version 7.4e.1 (Build 5) by Release_Master 05/27/05 04:53:11" } ) }
44
+ end
45
+
46
+
47
+ context "when parsing System Capabilities TLV" do
48
+ let( :data ) { [ 0x0e, 0x04, 0x00, 0x14, 0x00, 0x14 ].pack( "C*" ) }
49
+
50
+ its( :tlv_type ) { should eq 7 }
51
+ its( :tlv_info_length ) { should eq 4 }
52
+ its( :tlv_value ) { should eq( { "system_capabilities" => 20, "enabled_capabilities" => 20 } ) }
53
+ end
54
+
55
+
56
+ context "when parsing Management Address TLV" do
57
+ let( :data ) { [ 0x10, 0x0e, 0x07, 0x06, 0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0, 0x02, 0x00, 0x00, 0x03, 0xe9, 0x00 ].pack( "C*" ) }
58
+
59
+ its( :tlv_type ) { should eq 8 }
60
+ its( :tlv_info_length ) { should eq 14 }
61
+ its( :tlv_value ) { should eq( { "management_address" => "\a\006" } ) } # FIXME
62
+ end
63
+
64
+
65
+ context "when parsing Organizationally Specific TLV" do
66
+ let( :data ) { [ 0xfe, 0x07, 0x00, 0x12, 0x0f, 0x02, 0x07, 0x01, 0x00 ].pack( "C*" ) }
67
+
68
+ its( :tlv_type ) { should eq 127 }
69
+ its( :tlv_info_length ) { should eq 7 }
70
+ its( :tlv_value ) { should eq "" } # FIXME
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+ ### Local variables:
78
+ ### mode: Ruby
79
+ ### coding: utf-8-unix
80
+ ### indent-tabs-mode: nil
81
+ ### End:
@@ -0,0 +1,27 @@
1
+ require File.join( File.dirname( __FILE__ ), "..", "..", "spec_helper" )
2
+ require "pio/lldp/port-id-tlv"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ describe PortIdTlv do
8
+ subject { PortIdTlv.read( data.pack( "C*" ) ) }
9
+
10
+ context "parsing a raw data" do
11
+ let( :data ) { [ 0x04, 0x0d, 0x01, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x31 ] }
12
+
13
+ its( :tlv_type ) { should eq 2 }
14
+ its( :tlv_info_length ) { should eq 13 }
15
+ its( :subtype ) { should eq 1 }
16
+ its( :port_id ) { should eq data[ -12..-1 ].pack( "C*" ) }
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+
23
+ ### Local variables:
24
+ ### mode: Ruby
25
+ ### coding: utf-8-unix
26
+ ### indent-tabs-mode: nil
27
+ ### End:
@@ -0,0 +1,26 @@
1
+ require File.join( File.dirname( __FILE__ ), "..", "..", "spec_helper" )
2
+ require "pio/lldp/ttl-tlv"
3
+
4
+
5
+ module Pio
6
+ class Lldp
7
+ describe TtlTlv do
8
+ subject { TtlTlv.read( data.pack( "C*" ) ) }
9
+
10
+ context "parsing a raw data" do
11
+ let( :data ) { [ 0x06, 0x02, 0x00, 0x78 ] }
12
+
13
+ its( :tlv_type ) { should eq 3 }
14
+ its( :tlv_info_length ) { should eq 2 }
15
+ its( :ttl ) { should eq data[ -2..-1 ].pack( "C*" ) }
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+ ### Local variables:
23
+ ### mode: Ruby
24
+ ### coding: utf-8-unix
25
+ ### indent-tabs-mode: nil
26
+ ### End: