From 647f432213e0086a07ec3ce0b711ee0f568258cf Mon Sep 17 00:00:00 2001 From: shun159 Date: Fri, 27 Nov 2015 05:41:20 +0900 Subject: [PATCH 1/2] Add support for NXAST_LEARN --- features/open_flow13/nicira_learn.feature | 22 +++++++++++ lib/pio/open_flow13.rb | 1 + lib/pio/open_flow13/nicira_flow_mod_specs.rb | 26 +++++++++++++ lib/pio/open_flow13/nicira_learn.rb | 41 ++++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 features/open_flow13/nicira_learn.feature create mode 100644 lib/pio/open_flow13/nicira_flow_mod_specs.rb create mode 100644 lib/pio/open_flow13/nicira_learn.rb diff --git a/features/open_flow13/nicira_learn.feature b/features/open_flow13/nicira_learn.feature new file mode 100644 index 00000000..0b7a2f61 --- /dev/null +++ b/features/open_flow13/nicira_learn.feature @@ -0,0 +1,22 @@ +@openflow13 +Feature: NiciraLearn + + This action adds or modifies a flow in an OpenFlow table, similar to + OFPT_FLOW_MOD with OFPFC_MODIFY_STRICT as 'command'. + + Scenario: new({}) + When I try to create an OpenFlow action with: + """ + Pio::OpenFlow::NiciraLearn.new({}) + """ + Then it should finish successfully + And the action has the following fields and values: + | field | value | + | idle_timeout | 0 | + | hard_timeout | 0 | + | priority | 65535 | + | cookie | 0 | + | flags | [] | + | table_id | 0 | + | fin_idle_timeout | 0 | + | fin_hard_timeout | 0 | diff --git a/lib/pio/open_flow13.rb b/lib/pio/open_flow13.rb index 5294c99f..d28dd82c 100644 --- a/lib/pio/open_flow13.rb +++ b/lib/pio/open_flow13.rb @@ -23,6 +23,7 @@ require 'pio/open_flow13/nicira_send_out_port' require 'pio/open_flow13/nicira_stack_pop' require 'pio/open_flow13/nicira_stack_push' +require 'pio/open_flow13/nicira_learn' require 'pio/open_flow13/send_out_port' require 'pio/open_flow13/set_arp_operation' require 'pio/open_flow13/set_arp_sender_hardware_address' diff --git a/lib/pio/open_flow13/nicira_flow_mod_specs.rb b/lib/pio/open_flow13/nicira_flow_mod_specs.rb new file mode 100644 index 00000000..39d7b596 --- /dev/null +++ b/lib/pio/open_flow13/nicira_flow_mod_specs.rb @@ -0,0 +1,26 @@ +module Pio + module OpenFlow13 + # OpenFlow 1.3 FlowModSpecs + class NiciraFlowModSpecs < BinData::Primitive + endian :big + + count_bytes_remaining :instructions_length + string :instructions, read_length: :instructions_length + + def set(instructions) + self.instructions = Array(instructions).map(&:to_binary_s).join + end + + def get + list = [] + tmp = instructions + list << instruction while tmp.length > 0 + list + end + + def length + instructions.length + end + end + end +end diff --git a/lib/pio/open_flow13/nicira_learn.rb b/lib/pio/open_flow13/nicira_learn.rb new file mode 100644 index 00000000..9d035bf5 --- /dev/null +++ b/lib/pio/open_flow13/nicira_learn.rb @@ -0,0 +1,41 @@ +require 'pio/open_flow' + +module Pio + module OpenFlow13 + # NXAST_LEARN action + class NiciraLearn < OpenFlow::NiciraAction + extend OpenFlow::Flags + + flags_16bit :flags, [:send_flow_rem, + :delete_learned] + + nicira_action_header action_type: 0xffff, + action_length: 24, + subtype: 16 + uint16 :idle_timeout + uint16 :hard_timeout + uint16 :priority, initial_value: 0xffff + uint64 :cookie + flags :flags + uint8 :table_id + string :padding1, length: 1 + hide :padding1 + uint16 :fin_idle_timeout + uint16 :fin_hard_timeout + string :padding2, length: 2 + hide :padding2 + + def fms_length + if flow_mod_specs.size > 0 + flow_mod_specs.map(&:length).inject(&:+) + else + 0 + end + end + + def padding_length + (22 + 7) / 8 * 8 - 22 + end + end + end +end From 51cb8ca7f9c230ca4161aef11b997cfd6f589dde Mon Sep 17 00:00:00 2001 From: shun159 Date: Mon, 30 Nov 2015 01:06:09 +0900 Subject: [PATCH 2/2] Add src: 0, dst: 0 --- lib/pio/open_flow13.rb | 1 + lib/pio/open_flow13/learn_match.rb | 114 +++++++++++++++++++ lib/pio/open_flow13/nicira_flow_mod_specs.rb | 26 ----- lib/pio/open_flow13/nicira_learn.rb | 1 + 4 files changed, 116 insertions(+), 26 deletions(-) create mode 100644 lib/pio/open_flow13/learn_match.rb delete mode 100644 lib/pio/open_flow13/nicira_flow_mod_specs.rb diff --git a/lib/pio/open_flow13.rb b/lib/pio/open_flow13.rb index d28dd82c..d8581da3 100644 --- a/lib/pio/open_flow13.rb +++ b/lib/pio/open_flow13.rb @@ -24,6 +24,7 @@ require 'pio/open_flow13/nicira_stack_pop' require 'pio/open_flow13/nicira_stack_push' require 'pio/open_flow13/nicira_learn' +require 'pio/open_flow13/learn_match' require 'pio/open_flow13/send_out_port' require 'pio/open_flow13/set_arp_operation' require 'pio/open_flow13/set_arp_sender_hardware_address' diff --git a/lib/pio/open_flow13/learn_match.rb b/lib/pio/open_flow13/learn_match.rb new file mode 100644 index 00000000..ad07a7c0 --- /dev/null +++ b/lib/pio/open_flow13/learn_match.rb @@ -0,0 +1,114 @@ +require 'bindata' +require 'forwardable' +require 'pio/open_flow13/match' + +module Pio + module OpenFlow13 + class LearnMatch + extend Forwardable + + # 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 + @frame = Field.new(registers.merge(options)) + end + # rubocop:enable MethodLength + + attr_reader :source + attr_reader :destination + + def_delegator :@frame, :to_binary_s + + def self.read(raw_data) + begin + frame = Field.read(raw_data) + rescue + raise Pio::ParseError, $ERROR_INFO.message + end + + field = allocate + field.instance_variable_set :@frame, frame + field + end + + 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 + + class Field < BinData::Record + endian :big + + bit2 :zero + hide :zero + bit1 :src_type, value: 0 + hide :src_type + bit2 :dst_type, value: 0 + hide :dst_type + + bit11 :_n_bits + struct :_source do + uint16 :oxm_class + bit7 :oxm_field + bit1 :oxm_hasmask, value: 0 + uint8 :oxm_length + end + uint16 :source_offset + struct :_destination do + uint16 :oxm_class + bit7 :oxm_field + bit1 :oxm_hasmask, value: 0 + uint8 :oxm_length + end + uint16 :destination_offset + end + end + end +end diff --git a/lib/pio/open_flow13/nicira_flow_mod_specs.rb b/lib/pio/open_flow13/nicira_flow_mod_specs.rb deleted file mode 100644 index 39d7b596..00000000 --- a/lib/pio/open_flow13/nicira_flow_mod_specs.rb +++ /dev/null @@ -1,26 +0,0 @@ -module Pio - module OpenFlow13 - # OpenFlow 1.3 FlowModSpecs - class NiciraFlowModSpecs < BinData::Primitive - endian :big - - count_bytes_remaining :instructions_length - string :instructions, read_length: :instructions_length - - def set(instructions) - self.instructions = Array(instructions).map(&:to_binary_s).join - end - - def get - list = [] - tmp = instructions - list << instruction while tmp.length > 0 - list - end - - def length - instructions.length - end - end - end -end diff --git a/lib/pio/open_flow13/nicira_learn.rb b/lib/pio/open_flow13/nicira_learn.rb index 9d035bf5..cd7b547d 100644 --- a/lib/pio/open_flow13/nicira_learn.rb +++ b/lib/pio/open_flow13/nicira_learn.rb @@ -22,6 +22,7 @@ class NiciraLearn < OpenFlow::NiciraAction hide :padding1 uint16 :fin_idle_timeout uint16 :fin_hard_timeout + array :flow_mod_specs, type: :uint16, initial_length: 0 string :padding2, length: 2 hide :padding2