diff --git a/Rakefile b/Rakefile index f2066f58..1ec4910c 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,7 @@ require 'bundler/gem_tasks' RELISH_PROJECT = 'trema/pio' -FLAY_THRESHOLD = 1343 +FLAY_THRESHOLD = 1204 task default: :travis task test: [:spec, :cucumber] diff --git a/features/open_flow13/nicira_reg_move.feature b/features/open_flow13/nicira_reg_move.feature index 490e846d..34e10136 100644 --- a/features/open_flow13/nicira_reg_move.feature +++ b/features/open_flow13/nicira_reg_move.feature @@ -1,42 +1,51 @@ @open_flow13 Feature: Pio::NiciraRegMove - Scenario: new(from: :arp_sender_hardware_address, to: :arp_target_hardware_address) + Copies source[source_offset:sourcce_offset+n_bits] to + destination[destination_offset:dst_ofs+n_bits], where a[b:c] denotes + the bits within 'a' numbered 'b' through 'c' (not including bit 'c'). + + Scenario: new(source: :arp_sender_hardware_address, destination: :arp_target_hardware_address) When I try to create an OpenFlow action with: """ - Pio::NiciraRegMove.new(from: :arp_sender_hardware_address, to: :arp_target_hardware_address) + Pio::NiciraRegMove.new(source: :arp_sender_hardware_address, + destination: :arp_target_hardware_address) """ Then it should finish successfully And the action has the following fields and values: - | field | value | - | action_type.to_hex | 0xffff | - | action_length | 24 | - | experimenter_id.to_hex | 0x2320 | - | experimenter_type | 6 | - | from | :arp_sender_hardware_address | - | source_oxm_field | 24 | - | source_oxm_length | 6 | - | to | :arp_target_hardware_address | - | destination_oxm_field | 25 | - | destination_oxm_length | 6 | + | field | value | + | n_bits | 48 | + | source | :arp_sender_hardware_address | + | source_offset | 0 | + | destination | :arp_target_hardware_address | + | destination_offset | 0 | - Scenario: new(from: :reg0, to: :reg7) + Scenario: new(source: :reg0, destination: :reg7) + When I try to create an OpenFlow action with: + """ + Pio::NiciraRegMove.new(source: :reg0, destination: :reg7) + """ + Then it should finish successfully + And the action has the following fields and values: + | field | value | + | n_bits | 32 | + | source | :reg0 | + | source_offset | 0 | + | destination | :reg7 | + | destination_offset | 0 | + + Scenario: new(source: :reg0, source_offset: 16, destination: :reg7, destination_offset: 16, n_bits: 16) When I try to create an OpenFlow action with: """ - Pio::NiciraRegMove.new(from: :reg0, to: :reg7) + Pio::NiciraRegMove.new(source: :reg0, source_offset: 16, + destination: :reg7, destination_offset: 16, + n_bits: 16) """ Then it should finish successfully And the action has the following fields and values: - | field | value | - | action_type.to_hex | 0xffff | - | action_length | 24 | - | experimenter_id.to_hex | 0x2320 | - | experimenter_type | 6 | - | from | :reg0 | - | source_oxm_class | 1 | - | source_oxm_field | 0 | - | source_oxm_length | 4 | - | to | :reg7 | - | destination_oxm_class | 1 | - | destination_oxm_field | 7 | - | destination_oxm_length | 4 | + | field | value | + | n_bits | 16 | + | source | :reg0 | + | source_offset | 16 | + | destination | :reg7 | + | destination_offset | 16 | diff --git a/features/open_flow13/nicira_send_out_port.feature b/features/open_flow13/nicira_send_out_port.feature index 8ddf50c8..0ca4a6e0 100644 --- a/features/open_flow13/nicira_send_out_port.feature +++ b/features/open_flow13/nicira_send_out_port.feature @@ -8,13 +8,8 @@ Feature: Pio::NiciraSendOutPort """ Then it should finish successfully And the action has the following fields and values: - | field | value | - | action_type.to_hex | 0xffff | - | action_length | 24 | - | experimenter_id.to_hex | 0x2320 | - | experimenter_type | 15 | - | offset | 0 | - | source | :reg0 | - | max_length | 0 | - - + | field | value | + | offset | 0 | + | n_bits | 32 | + | source | :reg0 | + | max_length | 0 | diff --git a/lib/pio/open_flow13/nicira_reg_load.rb b/lib/pio/open_flow13/nicira_reg_load.rb index 0cd0fa2d..3e9b74d9 100644 --- a/lib/pio/open_flow13/nicira_reg_load.rb +++ b/lib/pio/open_flow13/nicira_reg_load.rb @@ -44,7 +44,7 @@ def value private def oxm_class - destination_oxm_class.superclass.const_get(:OXM_CLASS) + destination_oxm_class.const_get(:OXM_CLASS) end def oxm_field diff --git a/lib/pio/open_flow13/nicira_reg_move.rb b/lib/pio/open_flow13/nicira_reg_move.rb index 524406b9..072efca0 100644 --- a/lib/pio/open_flow13/nicira_reg_move.rb +++ b/lib/pio/open_flow13/nicira_reg_move.rb @@ -1,42 +1,84 @@ -require 'active_support/core_ext/string/inflections' -require 'pio/open_flow/action' +require 'pio/open_flow/nicira_action' +require 'pio/open_flow13/match' module Pio module OpenFlow13 # NXAST_REG_MOVE action - class NiciraRegMove < OpenFlow::Action - action_header action_type: 0xffff, action_length: 24 - uint32 :experimenter_id, value: 0x2320 - uint16 :experimenter_type, value: 6 - uint16 :n_bits, initial_value: -> { source_oxm_length * 8 } - uint16 :source_offset, value: 0 - uint16 :destination_offset, value: 0 - uint16 :source_oxm_class - bit7 :source_oxm_field - bit1 :source_oxm_hasmask, value: 0 - uint8 :source_oxm_length - uint16 :destination_oxm_class - bit7 :destination_oxm_field - bit1 :destination_oxm_hasmask, value: 0 - uint8 :destination_oxm_length - - attr_reader :from - attr_reader :to - - # rubocop:disable AbcSize - def initialize(options) - @from = options.fetch(:from) - @to = options.fetch(:to) - from_klass = Match.const_get(@from.to_s.classify) - to_klass = Match.const_get(@to.to_s.classify) - super(source_oxm_class: from_klass.superclass.const_get(:OXM_CLASS), - source_oxm_field: from_klass.const_get(:OXM_FIELD), - source_oxm_length: from_klass.new.length, - destination_oxm_class: to_klass.superclass.const_get(:OXM_CLASS), - destination_oxm_field: to_klass.const_get(:OXM_FIELD), - destination_oxm_length: to_klass.new.length) - end - # rubocop:enable AbcSize + class NiciraRegMove < OpenFlow::NiciraAction + nicira_action_header action_type: 0xffff, + action_length: 24, + subtype: 6 + uint16 :n_bits, initial_value: -> { _source[:oxm_length] * 8 } + uint16 :source_offset, initial_value: 0 + uint16 :destination_offset, initial_value: 0 + struct :_source do + uint16 :oxm_class + bit7 :oxm_field + bit1 :oxm_hasmask, value: 0 + uint8 :oxm_length + end + struct :_destination do + uint16 :oxm_class + bit7 :oxm_field + bit1 :oxm_hasmask, value: 0 + uint8 :oxm_length + end + + # rubocop:disable MethodLength + def initialize(arguments) + @source = arguments.fetch(:source) + @destination = arguments.fetch(:destination) + registers = { _source: { oxm_class: source_oxm_class, + oxm_field: source_oxm_field, + oxm_length: source_oxm_length }, + _destination: { oxm_class: destination_oxm_class, + oxm_field: destination_oxm_field, + oxm_length: destination_oxm_length } } + options = [:n_bits, + :source_offset, + :destination_offset].each_with_object({}) do |each, opts| + opts[each] = arguments[each] if arguments[each] + end + super registers.merge(options) + end + # rubocop:enable MethodLength + + attr_reader :source + attr_reader :destination + + private + + def source_oxm_class + source_class.const_get(:OXM_CLASS) + end + + def source_oxm_field + source_class.const_get(:OXM_FIELD) + end + + def source_oxm_length + source_class.new.length + end + + def source_class + Match.const_get(@source.to_s.split('_').map(&:capitalize).join) + end + + def destination_oxm_class + destination_class.const_get(:OXM_CLASS) + end + + def destination_oxm_field + destination_class.const_get(:OXM_FIELD) + end + + def destination_oxm_length + destination_class.new.length + end + + def destination_class + Match.const_get(@destination.to_s.split('_').map(&:capitalize).join) + end end end end diff --git a/lib/pio/open_flow13/nicira_send_out_port.rb b/lib/pio/open_flow13/nicira_send_out_port.rb index dfdbdbb7..5bbd9765 100644 --- a/lib/pio/open_flow13/nicira_send_out_port.rb +++ b/lib/pio/open_flow13/nicira_send_out_port.rb @@ -1,37 +1,57 @@ -require 'pio/open_flow/action' +require 'pio/open_flow/nicira_action' +require 'pio/open_flow13/match' module Pio module OpenFlow13 # NXAST_OUTPUT_REG action - class NiciraSendOutPort < OpenFlow::Action - action_header action_type: 0xffff, action_length: 24 - uint32 :experimenter_id, value: 0x2320 - uint16 :experimenter_type, value: 15 - bit10 :offset_internal, value: 0 - bit6 :n_bits_internal - uint32 :source_internal + class NiciraSendOutPort < OpenFlow::NiciraAction + nicira_action_header action_type: 0xffff, + action_length: 24, + subtype: 15 + bit10 :_offset, value: 0 + bit6 :_n_bits + struct :_source do + uint16 :oxm_class + bit9 :oxm_field + bit7 :oxm_length + end uint16 :max_length, value: 0 string :zero, length: 6 - attr_reader :source - - # rubocop:disable AbcSize - # rubocop:disable LineLength def initialize(source) @source = source - oxm_klass = Match.const_get(source.to_s.split('_').map(&:capitalize).join) - super(n_bits_internal: oxm_klass.new.length * 8 - 1, - source_internal: ((oxm_klass.superclass.const_get(:OXM_CLASS) << 16) | (oxm_klass.const_get(:OXM_FIELD) << 9) | oxm_klass.new.length)) + super(_n_bits: oxm_length * 8 - 1, + _source: { oxm_class: oxm_class, + oxm_field: oxm_field, + oxm_length: oxm_length }) end - # rubocop:enable AbcSize - # rubocop:enable LineLength + + attr_reader :source def offset - offset_internal + _offset end def n_bits - n_bits_internal + 1 + _n_bits + 1 + end + + private + + def oxm_class + source_oxm_class.const_get(:OXM_CLASS) + end + + def oxm_field + source_oxm_class.const_get(:OXM_FIELD) + end + + def oxm_length + source_oxm_class.new.length + end + + def source_oxm_class + Match.const_get(@source.to_s.split('_').map(&:capitalize).join) end end end diff --git a/spec/pio/open_flow13/nicira_reg_move_spec.rb b/spec/pio/open_flow13/nicira_reg_move_spec.rb new file mode 100644 index 00000000..729dfad5 --- /dev/null +++ b/spec/pio/open_flow13/nicira_reg_move_spec.rb @@ -0,0 +1,40 @@ +require 'pio/open_flow13/nicira_reg_move' + +describe Pio::OpenFlow13::NiciraRegMove do + describe '.new' do + When(:nicira_reg_move) do + Pio::OpenFlow13::NiciraRegMove.new(options) + end + + context 'with source: :arp_sender_hardware_address,'\ + ' destination: :arp_target_hardware_address' do + Given(:options) do + { source: :arp_sender_hardware_address, + destination: :arp_target_hardware_address } + end + + Invariant do + nicira_reg_move.n_bits == + nicira_reg_move._source[:oxm_length] * 8 + end + + Then { nicira_reg_move.action_type == 0xffff } + Then { nicira_reg_move.action_length == 24 } + Then { nicira_reg_move.vendor == 0x2320 } + Then { nicira_reg_move.subtype == 6 } + Then { nicira_reg_move.n_bits == 48 } + Then { nicira_reg_move.source_offset == 0 } + Then { nicira_reg_move.destination_offset == 0 } + Then { nicira_reg_move.source == :arp_sender_hardware_address } + Then { nicira_reg_move._source[:oxm_class] == 0x8000 } + Then { nicira_reg_move._source[:oxm_field] == 24 } + Then { nicira_reg_move._source[:oxm_hasmask] == 0 } + Then { nicira_reg_move._source[:oxm_length] == 6 } + Then { nicira_reg_move.destination == :arp_target_hardware_address } + Then { nicira_reg_move._destination[:oxm_class] == 0x8000 } + Then { nicira_reg_move._destination[:oxm_field] == 25 } + Then { nicira_reg_move._destination[:oxm_hasmask] == 0 } + Then { nicira_reg_move._destination[:oxm_length] == 6 } + end + end +end diff --git a/spec/pio/open_flow13/nicira_send_out_port_spec.rb b/spec/pio/open_flow13/nicira_send_out_port_spec.rb new file mode 100644 index 00000000..d8c9b9ab --- /dev/null +++ b/spec/pio/open_flow13/nicira_send_out_port_spec.rb @@ -0,0 +1,29 @@ +require 'pio/open_flow13/nicira_send_out_port' + +describe Pio::OpenFlow13::NiciraSendOutPort do + describe '.new' do + When(:nicira_send_out_port) do + Pio::OpenFlow13::NiciraSendOutPort.new(source) + end + + context 'with :reg0' do + Given(:source) { :reg0 } + + Invariant do + nicira_send_out_port.n_bits == + nicira_send_out_port._source[:oxm_length] * 8 + end + + Then { nicira_send_out_port.action_type == 0xffff } + Then { nicira_send_out_port.action_length == 24 } + Then { nicira_send_out_port.vendor == 0x2320 } + Then { nicira_send_out_port.subtype == 15 } + Then { nicira_send_out_port.offset == 0 } + Then { nicira_send_out_port.n_bits == 32 } + Then { nicira_send_out_port.source == :reg0 } + Then { nicira_send_out_port._source[:oxm_class] == 1 } + Then { nicira_send_out_port._source[:oxm_field] == 0 } + Then { nicira_send_out_port._source[:oxm_length] == 4 } + end + end +end