pio 0.9.0 → 0.10.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 +6 -0
- data/README.md +36 -0
- data/examples/packet_out_new.rb +18 -0
- data/examples/packet_out_read.rb +6 -0
- data/features/packet_out_read.feature +5 -0
- data/lib/pio.rb +1 -0
- data/lib/pio/echo.rb +5 -6
- data/lib/pio/echo/message.rb +39 -13
- data/lib/pio/echo/reply.rb +1 -6
- data/lib/pio/echo/request.rb +3 -5
- data/lib/pio/enqueue.rb +62 -0
- data/lib/pio/features.rb +5 -15
- data/lib/pio/features/reply.rb +28 -48
- data/lib/pio/features/request.rb +11 -8
- data/lib/pio/hello.rb +24 -2
- data/lib/pio/monkey_patch/integer.rb +6 -0
- data/lib/pio/monkey_patch/integer/ranges.rb +22 -0
- data/lib/pio/open_flow.rb +1 -0
- data/lib/pio/open_flow/flags.rb +40 -26
- data/lib/pio/open_flow/message.rb +28 -0
- data/lib/pio/open_flow/parser.rb +22 -0
- data/lib/pio/open_flow/phy_port.rb +34 -50
- data/lib/pio/open_flow/port_number.rb +39 -0
- data/lib/pio/open_flow/type.rb +1 -0
- data/lib/pio/packet_in.rb +42 -9
- data/lib/pio/packet_out.rb +102 -0
- data/lib/pio/send_out_port.rb +74 -0
- data/lib/pio/set_eth_addr.rb +52 -0
- data/lib/pio/set_ip_addr.rb +49 -0
- data/lib/pio/set_ip_tos.rb +42 -0
- data/lib/pio/set_transport_port.rb +58 -0
- data/lib/pio/set_vlan.rb +37 -0
- data/lib/pio/set_vlan_priority.rb +18 -0
- data/lib/pio/set_vlan_vid.rb +30 -0
- data/lib/pio/strip_vlan_header.rb +19 -0
- data/lib/pio/type/ip_address.rb +11 -2
- data/lib/pio/type/ipv4_header.rb +1 -0
- data/lib/pio/type/mac_address.rb +2 -0
- data/lib/pio/version.rb +1 -1
- data/pio.gemspec +4 -4
- data/spec/pio/echo/reply_spec.rb +1 -4
- data/spec/pio/echo/request_spec.rb +5 -8
- data/spec/pio/enqueue_spec.rb +67 -0
- data/spec/pio/features/request_spec.rb +4 -4
- data/spec/pio/features_spec.rb +1 -2
- data/spec/pio/hello_spec.rb +1 -4
- data/spec/pio/packet_out_spec.rb +290 -0
- data/spec/pio/send_out_port_spec.rb +121 -0
- data/spec/pio/set_eth_dst_addr_spec.rb +28 -0
- data/spec/pio/set_eth_src_addr_spec.rb +28 -0
- data/spec/pio/set_ip_dst_addr_spec.rb +25 -0
- data/spec/pio/set_ip_src_addr_spec.rb +25 -0
- data/spec/pio/set_ip_tos_spec.rb +30 -0
- data/spec/pio/set_transport_dst_port_spec.rb +42 -0
- data/spec/pio/set_transport_src_port_spec.rb +42 -0
- data/spec/pio/set_vlan_priority_spec.rb +42 -0
- data/spec/pio/set_vlan_vid_spec.rb +42 -0
- data/spec/pio/strip_vlan_header_spec.rb +20 -0
- metadata +55 -13
- data/lib/pio/echo/format.rb +0 -22
- data/lib/pio/hello/format.rb +0 -18
- data/lib/pio/packet_in/format.rb +0 -55
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'pio/monkey_patch/integer'
|
4
|
+
|
5
|
+
module Pio
|
6
|
+
# An action to output a packet to a port.
|
7
|
+
class SendOutPort
|
8
|
+
# OpenFlow 1.0 OFPAT_OUTPUT action format.
|
9
|
+
class Format < BinData::Record
|
10
|
+
endian :big
|
11
|
+
|
12
|
+
uint16 :type, value: 0
|
13
|
+
uint16 :message_length, value: 8
|
14
|
+
port_number :port_number
|
15
|
+
uint16 :max_len, initial_value: 2**16 - 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.read(raw_data)
|
19
|
+
send_out_port = allocate
|
20
|
+
send_out_port.instance_variable_set :@format, Format.read(raw_data)
|
21
|
+
send_out_port
|
22
|
+
end
|
23
|
+
|
24
|
+
extend Forwardable
|
25
|
+
|
26
|
+
def_delegators :@format, :message_length
|
27
|
+
def_delegators :@format, :port_number
|
28
|
+
def_delegators :@format, :max_len
|
29
|
+
def_delegator :@format, :to_binary_s, :to_binary
|
30
|
+
|
31
|
+
# Creates an action to output a packet to a port.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# SendOutPort.new(1)
|
35
|
+
# SendOutPort.new(port_number: 1)
|
36
|
+
# SendOutPort.new(port_number: :controller, max_len: 256)
|
37
|
+
#
|
38
|
+
# @param [Integer|Hash] user_options
|
39
|
+
# the port number or the options hash to create this action
|
40
|
+
# class instance with.
|
41
|
+
#
|
42
|
+
# @option user_options [Number] :port_number
|
43
|
+
# port number an index into switch's physical port list. There
|
44
|
+
# are also fake output ports. For example a port number set to
|
45
|
+
# +:flood+ would output packets to all physical ports except
|
46
|
+
# input port and ports disabled by STP.
|
47
|
+
# @option user_options [Number] :max_len
|
48
|
+
# the maximum number of bytes from a packet to send to
|
49
|
+
# controller when port is set to +:controller+. A zero length
|
50
|
+
# means no bytes of the packet should be sent. It defaults to
|
51
|
+
# 64K.
|
52
|
+
#
|
53
|
+
# @raise [ArgumentError] if +:port_number+ is not an unsigned
|
54
|
+
# 16-bit integer.
|
55
|
+
# @raise [ArgumentError] if +:max_len+ is not an unsigned 16-bit integer.
|
56
|
+
#
|
57
|
+
# rubocop:disable MethodLength
|
58
|
+
def initialize(user_options)
|
59
|
+
options = if user_options.respond_to?(:to_i)
|
60
|
+
{ port_number: user_options.to_i }
|
61
|
+
elsif PortNumber::NUMBERS.key?(user_options)
|
62
|
+
{ port_number: user_options }
|
63
|
+
else
|
64
|
+
user_options
|
65
|
+
end
|
66
|
+
max_len = options[:max_len]
|
67
|
+
if max_len && !max_len.unsigned_16bit?
|
68
|
+
fail ArgumentError, 'The max_len should be an unsigned 16bit integer.'
|
69
|
+
end
|
70
|
+
@format = Format.new(options)
|
71
|
+
end
|
72
|
+
# rubocop:enable MethodLength
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'pio/type/mac_address'
|
4
|
+
|
5
|
+
module Pio
|
6
|
+
# An action to modify the source/destination Ethernet address of a packet.
|
7
|
+
class SetEthAddr
|
8
|
+
# rubocop:disable MethodLength
|
9
|
+
def self.def_format(action_type)
|
10
|
+
str = %(
|
11
|
+
class Format < BinData::Record
|
12
|
+
endian :big
|
13
|
+
|
14
|
+
uint16 :type, value: #{action_type}
|
15
|
+
uint16 :message_length, value: 16
|
16
|
+
mac_address :mac_address
|
17
|
+
uint48 :padding
|
18
|
+
hide :padding
|
19
|
+
end
|
20
|
+
)
|
21
|
+
module_eval str
|
22
|
+
end
|
23
|
+
# rubocop:enable MethodLength
|
24
|
+
|
25
|
+
def self.read(raw_data)
|
26
|
+
set_eth_addr = allocate
|
27
|
+
set_eth_addr.instance_variable_set(:@format,
|
28
|
+
const_get(:Format).read(raw_data))
|
29
|
+
set_eth_addr
|
30
|
+
end
|
31
|
+
|
32
|
+
extend Forwardable
|
33
|
+
|
34
|
+
def_delegators :@format, :message_length
|
35
|
+
def_delegators :@format, :mac_address
|
36
|
+
def_delegator :@format, :to_binary_s, :to_binary
|
37
|
+
|
38
|
+
def initialize(mac_address)
|
39
|
+
@format = self.class.const_get(:Format).new(mac_address: mac_address)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# An action to modify the source Ethernet address of a packet.
|
44
|
+
class SetEthSrcAddr < SetEthAddr
|
45
|
+
def_format 4
|
46
|
+
end
|
47
|
+
|
48
|
+
# An action to modify the destination Ethernet address of a packet.
|
49
|
+
class SetEthDstAddr < SetEthAddr
|
50
|
+
def_format 5
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'pio/type/ip_address'
|
4
|
+
|
5
|
+
module Pio
|
6
|
+
# An action to modify the IPv4 source/destination address of a packet.
|
7
|
+
class SetIpAddr
|
8
|
+
def self.def_format(action_type)
|
9
|
+
str = %(
|
10
|
+
class Format < BinData::Record
|
11
|
+
endian :big
|
12
|
+
|
13
|
+
uint16 :type, value: #{action_type}
|
14
|
+
uint16 :message_length, value: 8
|
15
|
+
ip_address :ip_address
|
16
|
+
end
|
17
|
+
)
|
18
|
+
module_eval str
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.read(raw_data)
|
22
|
+
set_ip_addr = allocate
|
23
|
+
set_ip_addr.instance_variable_set(:@format,
|
24
|
+
const_get(:Format).read(raw_data))
|
25
|
+
set_ip_addr
|
26
|
+
end
|
27
|
+
|
28
|
+
extend Forwardable
|
29
|
+
|
30
|
+
def_delegators :@format, :type
|
31
|
+
def_delegators :@format, :message_length
|
32
|
+
def_delegators :@format, :ip_address
|
33
|
+
def_delegator :@format, :to_binary_s, :to_binary
|
34
|
+
|
35
|
+
def initialize(ip_address)
|
36
|
+
@format = self.class.const_get(:Format).new(ip_address: ip_address)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# An action to modify the IPv4 source address of a packet.
|
41
|
+
class SetIpSrcAddr < SetIpAddr
|
42
|
+
def_format 6
|
43
|
+
end
|
44
|
+
|
45
|
+
# An action to modify the IPv4 source address of a packet.
|
46
|
+
class SetIpDstAddr < SetIpAddr
|
47
|
+
def_format 7
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'pio/monkey_patch/integer'
|
4
|
+
|
5
|
+
module Pio
|
6
|
+
# An action to modify the IP ToS/DSCP field of a packet.
|
7
|
+
class SetIpTos
|
8
|
+
# OpenFlow 1.0 OFPAT_SET_NW_TOS action format.
|
9
|
+
class Format < BinData::Record
|
10
|
+
endian :big
|
11
|
+
|
12
|
+
uint16 :type, value: 8
|
13
|
+
uint16 :message_length, value: 8
|
14
|
+
uint8 :type_of_service
|
15
|
+
uint24 :padding
|
16
|
+
hide :padding
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.read(raw_data)
|
20
|
+
set_ip_tos = allocate
|
21
|
+
set_ip_tos.instance_variable_set :@format, Format.read(raw_data)
|
22
|
+
set_ip_tos
|
23
|
+
end
|
24
|
+
|
25
|
+
extend Forwardable
|
26
|
+
|
27
|
+
def_delegators :@format, :type
|
28
|
+
def_delegators :@format, :message_length
|
29
|
+
def_delegators :@format, :type_of_service
|
30
|
+
def_delegator :@format, :to_binary_s, :to_binary
|
31
|
+
|
32
|
+
def initialize(type_of_service)
|
33
|
+
# nw_tos (IP ToS) value consists of 8 bits, of which only the 6
|
34
|
+
# high-order bits belong to DSCP, the 2 low-order bits must be
|
35
|
+
# zero.
|
36
|
+
unless type_of_service.unsigned_8bit? && type_of_service % 4 == 0
|
37
|
+
fail ArgumentError, 'Invalid type_of_service (ToS) value.'
|
38
|
+
end
|
39
|
+
@format = Format.new(type_of_service: type_of_service)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'pio/monkey_patch/integer'
|
4
|
+
|
5
|
+
module Pio
|
6
|
+
# An action to modify the source/destination TCP/UDP port of a packet.
|
7
|
+
class SetTransportPort
|
8
|
+
# rubocop:disable MethodLength
|
9
|
+
def self.def_format(action_type)
|
10
|
+
str = %(
|
11
|
+
class Format < BinData::Record
|
12
|
+
endian :big
|
13
|
+
|
14
|
+
uint16 :type, value: #{action_type}
|
15
|
+
uint16 :message_length, value: 8
|
16
|
+
uint16 :port_number
|
17
|
+
uint16 :padding
|
18
|
+
hide :padding
|
19
|
+
end
|
20
|
+
)
|
21
|
+
module_eval str
|
22
|
+
end
|
23
|
+
# rubocop:enable MethodLength
|
24
|
+
|
25
|
+
def self.read(raw_data)
|
26
|
+
action = allocate
|
27
|
+
action.instance_variable_set(:@format, const_get(:Format).read(raw_data))
|
28
|
+
action
|
29
|
+
end
|
30
|
+
|
31
|
+
extend Forwardable
|
32
|
+
|
33
|
+
def_delegators :@format, :type
|
34
|
+
def_delegators :@format, :message_length
|
35
|
+
def_delegators :@format, :port_number
|
36
|
+
def_delegator :@format, :to_binary_s, :to_binary
|
37
|
+
|
38
|
+
def initialize(number)
|
39
|
+
port_number = number.to_i
|
40
|
+
unless port_number.unsigned_16bit?
|
41
|
+
fail ArgumentError, 'TCP/UDP port must be an unsigned 16-bit integer.'
|
42
|
+
end
|
43
|
+
@format = self.class.const_get(:Format).new(port_number: port_number)
|
44
|
+
rescue NoMethodError
|
45
|
+
raise TypeError, 'TCP/UDP port must be an unsigned 16-bit integer.'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# An action to modify the source TCP/UDP port of a packet.
|
50
|
+
class SetTransportSrcPort < SetTransportPort
|
51
|
+
def_format 9
|
52
|
+
end
|
53
|
+
|
54
|
+
# An action to modify the source TCP/UDP port of a packet.
|
55
|
+
class SetTransportDstPort < SetTransportPort
|
56
|
+
def_format 10
|
57
|
+
end
|
58
|
+
end
|
data/lib/pio/set_vlan.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Pio
|
5
|
+
# An action to modify the VLAN related fields of a packet.
|
6
|
+
class SetVlan
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# rubocop:disable MethodLength
|
10
|
+
def self.def_format(field_name, action_type)
|
11
|
+
str = %(
|
12
|
+
class Format < BinData::Record
|
13
|
+
endian :big
|
14
|
+
|
15
|
+
uint16 :type, value: #{action_type}
|
16
|
+
uint16 :message_length, value: 8
|
17
|
+
uint16 :#{field_name}
|
18
|
+
uint16 :padding
|
19
|
+
hide :padding
|
20
|
+
end
|
21
|
+
)
|
22
|
+
module_eval str
|
23
|
+
module_eval "def_delegators :@format, :#{field_name}"
|
24
|
+
end
|
25
|
+
# rubocop:enable MethodLength
|
26
|
+
|
27
|
+
def self.read(raw_data)
|
28
|
+
set_vlan = allocate
|
29
|
+
set_vlan.instance_variable_set :@format, const_get(:Format).read(raw_data)
|
30
|
+
set_vlan
|
31
|
+
end
|
32
|
+
|
33
|
+
def_delegators :@format, :type
|
34
|
+
def_delegators :@format, :message_length
|
35
|
+
def_delegator :@format, :to_binary_s, :to_binary
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pio/set_vlan'
|
2
|
+
|
3
|
+
module Pio
|
4
|
+
# An action to modify the VLAN priority of a packet.
|
5
|
+
class SetVlanPriority < SetVlan
|
6
|
+
def_format :vlan_priority, 2
|
7
|
+
|
8
|
+
def initialize(number)
|
9
|
+
priority = number.to_i
|
10
|
+
if priority < 0 || priority > 7
|
11
|
+
fail ArgumentError, 'VLAN priority must be between 0 and 7 inclusive'
|
12
|
+
end
|
13
|
+
@format = Format.new(vlan_priority: priority)
|
14
|
+
rescue NoMethodError
|
15
|
+
raise TypeError, 'VLAN priority must be an Integer.'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'pio/set_vlan'
|
2
|
+
|
3
|
+
module Pio
|
4
|
+
# An action to modify the VLAN ID of a packet.
|
5
|
+
class SetVlanVid < SetVlan
|
6
|
+
def_format :vlan_id, 1
|
7
|
+
|
8
|
+
# Creates an action to modify the VLAN ID of a packet. The VLAN ID
|
9
|
+
# is 16-bits long but the actual VID (VLAN Identifier) of the IEEE
|
10
|
+
# 802.1Q frame is 12-bits.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# ActionSetVlanVid.new(number)
|
14
|
+
#
|
15
|
+
# @param [Integer] number
|
16
|
+
# the VLAN ID to set to. Only the lower 12-bits are used.
|
17
|
+
#
|
18
|
+
# @raise [ArgumentError] if vlan_id not within 1 and 4095 inclusive.
|
19
|
+
# @raise [TypeError] if vlan_id is not an Integer.
|
20
|
+
def initialize(number)
|
21
|
+
vlan_id = number.to_i
|
22
|
+
unless vlan_id >= 1 && vlan_id <= 4095
|
23
|
+
fail ArgumentError, 'VLAN ID must be between 1 and 4095 inclusive'
|
24
|
+
end
|
25
|
+
@format = Format.new(vlan_id: vlan_id)
|
26
|
+
rescue NoMethodError
|
27
|
+
raise TypeError, 'VLAN ID must be an Integer.'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
module Pio
|
4
|
+
# An action to strip the 802.1q header.
|
5
|
+
class StripVlanHeader < BinData::Record
|
6
|
+
endian :big
|
7
|
+
|
8
|
+
uint16 :type, value: 3
|
9
|
+
uint16 :message_length, value: 8
|
10
|
+
uint32 :padding
|
11
|
+
hide :padding
|
12
|
+
|
13
|
+
alias_method :to_binary, :to_binary_s
|
14
|
+
|
15
|
+
def snapshot
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/pio/type/ip_address.rb
CHANGED
@@ -8,11 +8,20 @@ module Pio
|
|
8
8
|
array :octets, type: :uint8, initial_length: 4
|
9
9
|
|
10
10
|
def set(value)
|
11
|
-
|
11
|
+
case value
|
12
|
+
when String
|
13
|
+
self.octets = value.split('.').map(&:to_i)
|
14
|
+
else
|
15
|
+
self.octets = value
|
16
|
+
end
|
12
17
|
end
|
13
18
|
|
14
19
|
def get
|
15
|
-
IPv4Address.new octets.map { |
|
20
|
+
IPv4Address.new octets.map { |each| format('%d', each) }.join('.')
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
get == other
|
16
25
|
end
|
17
26
|
end
|
18
27
|
end
|
data/lib/pio/type/ipv4_header.rb
CHANGED
data/lib/pio/type/mac_address.rb
CHANGED
data/lib/pio/version.rb
CHANGED
data/pio.gemspec
CHANGED
@@ -37,11 +37,11 @@ Gem::Specification.new do |gem|
|
|
37
37
|
gem.add_dependency 'bindata', '~> 2.1.0'
|
38
38
|
|
39
39
|
gem.add_development_dependency 'rake'
|
40
|
-
gem.add_development_dependency 'bundler', '~> 1.7.
|
40
|
+
gem.add_development_dependency 'bundler', '~> 1.7.11'
|
41
41
|
gem.add_development_dependency 'pry', '~> 0.10.1'
|
42
42
|
|
43
43
|
# Guard
|
44
|
-
gem.add_development_dependency 'guard', '~> 2.10.
|
44
|
+
gem.add_development_dependency 'guard', '~> 2.10.5'
|
45
45
|
gem.add_development_dependency 'guard-bundler', '~> 2.1.0'
|
46
46
|
gem.add_development_dependency 'guard-cucumber', '~> 1.5.3'
|
47
47
|
gem.add_development_dependency 'guard-rspec', '~> 4.5.0'
|
@@ -56,9 +56,9 @@ Gem::Specification.new do |gem|
|
|
56
56
|
gem.add_development_dependency 'yard', '~> 0.8.7.6'
|
57
57
|
|
58
58
|
# Test
|
59
|
-
gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.
|
59
|
+
gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.4'
|
60
60
|
gem.add_development_dependency 'coveralls', '~> 0.7.2'
|
61
|
-
gem.add_development_dependency 'cucumber', '~> 1.3.
|
61
|
+
gem.add_development_dependency 'cucumber', '~> 1.3.18'
|
62
62
|
gem.add_development_dependency 'flay', '~> 2.5.0'
|
63
63
|
gem.add_development_dependency 'flog', '~> 4.3.0'
|
64
64
|
gem.add_development_dependency 'reek', '~> 1.5.1'
|