diff --git a/config/config.exs b/config/config.exs index c04ed23..d9cfaf3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -11,7 +11,7 @@ config :tres, callback_args: [] config :logger, - level: :debug, + level: :info, format: "$date $time [$level] $message\n", metadata: [], handle_otp_reports: true diff --git a/lib/openflow/actions/experimenter.ex b/lib/openflow/actions/experimenter.ex index b2b7e99..2ff6d3a 100644 --- a/lib/openflow/actions/experimenter.ex +++ b/lib/openflow/actions/experimenter.ex @@ -16,6 +16,23 @@ defmodule Openflow.Action.Experimenter do <<0xFFFF::16, length::16, exp_id::32, data::bytes>> end + @spec pack_exp_header(binary()) :: binary() + def pack_exp_header(exp_body) do + pad_length = + exp_body + |> Kernel.byte_size() + |> Kernel.+(4) + |> Openflow.Utils.padding(8) + + length = + exp_body + |> byte_size() + |> Kernel.+(4) + |> Kernel.+(pad_length) + + <<0xFFFF::16, length::16, exp_body::bytes, 0::size(pad_length)-unit(8)>> + end + def read(<<0xFFFF::16, _length::16, exp_id::32, exp_type::16, data::bytes>>) do case Openflow.Utils.get_enum(exp_id, :action_vendor) do vendor_id when is_integer(vendor_id) -> diff --git a/lib/openflow/actions/nx_bundle.ex b/lib/openflow/actions/nx_bundle.ex index da16230..04190a9 100644 --- a/lib/openflow/actions/nx_bundle.ex +++ b/lib/openflow/actions/nx_bundle.ex @@ -12,8 +12,9 @@ defmodule Openflow.Action.NxBundle do @nxast 12 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do + def new(options \\ []) do slaves = options[:slaves] || [] %NxBundle{ @@ -25,28 +26,25 @@ defmodule Openflow.Action.NxBundle do } end - def to_binary(%NxBundle{ - algorithm: alg, - hash_field: hash_field, - basis: basis, - slave_type: slave_type, - n_slaves: n_slaves, - slaves: slaves - }) do - hash_field_int = Openflow.Enums.to_int(hash_field, :nx_hash_fields) - alg_int = Openflow.Enums.to_int(alg, :nx_bd_algorithm) - slave_type_bin = Openflow.Match.codec_header(slave_type) - slaves_bin = codec_slaves(slaves) + def to_binary(%NxBundle{} = bundle) do + bundle_hash_field_int = Openflow.Enums.to_int(bundle.hash_field, :nx_hash_fields) + bundle_alg_int = Openflow.Enums.to_int(bundle.algorithm, :nx_bd_algorithm) + bundle_slave_type_bin = Openflow.Match.codec_header(bundle.slave_type) + bundle_slaves_bin = codec_slaves(bundle.slaves) - body = - <> - - exp_body = <<@experimenter::32, @nxast::16, body::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + bundle_alg_int::16, + bundle_hash_field_int::16, + bundle.basis::16, + bundle_slave_type_bin::4-bytes, + bundle.n_slaves::16, + 0::size(2)-unit(8), + 0::size(4)-unit(8), + 0::size(4)-unit(8), + bundle_slaves_bin::bytes + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_bundle_load.ex b/lib/openflow/actions/nx_bundle_load.ex index f213fe0..7548329 100644 --- a/lib/openflow/actions/nx_bundle_load.ex +++ b/lib/openflow/actions/nx_bundle_load.ex @@ -17,9 +17,10 @@ defmodule Openflow.Action.NxBundleLoad do @nxast 13 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - dst_field = options[:dst_field] + def new(options \\ []) do + dst_field = options[:dst_field] || raise "dst_field must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(dst_field) slaves = options[:slaves] || [] @@ -35,33 +36,27 @@ defmodule Openflow.Action.NxBundleLoad do } end - def to_binary(%NxBundleLoad{ - algorithm: alg, - hash_field: hash_field, - basis: basis, - slave_type: slave_type, - n_slaves: n_slaves, - slaves: slaves, - offset: ofs, - n_bits: n_bits, - dst_field: dst_field - }) do - hash_field_int = Openflow.Enums.to_int(hash_field, :nx_hash_fields) - alg_int = Openflow.Enums.to_int(alg, :nx_bd_algorithm) - slave_type_bin = Openflow.Match.codec_header(slave_type) - slaves_bin = codec_slaves(slaves) - ofs_nbits = ofs <<< 6 ||| n_bits - 1 - dst_field_bin = Openflow.Match.codec_header(dst_field) + def to_binary(%NxBundleLoad{} = bundle_load) do + hash_field_int = Openflow.Enums.to_int(bundle_load.hash_field, :nx_hash_fields) + alg_int = Openflow.Enums.to_int(bundle_load.algorithm, :nx_bd_algorithm) + slave_type_bin = Openflow.Match.codec_header(bundle_load.slave_type) + slaves_bin = codec_slaves(bundle_load.slaves) + ofs_nbits = bundle_load.offset <<< 6 ||| bundle_load.n_bits - 1 + dst_field_bin = Openflow.Match.codec_header(bundle_load.dst_field) - body = - <> - - exp_body = <<@experimenter::32, @nxast::16, body::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + alg_int::16, + hash_field_int::16, + bundle_load.basis::16, + slave_type_bin::4-bytes, + bundle_load.n_slaves::16, + ofs_nbits::16, + dst_field_bin::4-bytes, + 0::32, + slaves_bin::bytes + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_clone.ex b/lib/openflow/actions/nx_clone.ex index 971721b..939a558 100644 --- a/lib/openflow/actions/nx_clone.ex +++ b/lib/openflow/actions/nx_clone.ex @@ -5,6 +5,7 @@ defmodule Openflow.Action.NxClone do @nxast 42 alias __MODULE__ + alias Openflow.Action.Experimenter def new(actions \\ []) do %NxClone{actions: actions} @@ -12,11 +13,10 @@ defmodule Openflow.Action.NxClone do def to_binary(%NxClone{actions: actions}) do actions_bin = Openflow.Action.to_binary(actions) - exp_body = <<@experimenter::32, @nxast::16, 0::size(6)-unit(8), actions_bin::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + + Experimenter.pack_exp_header( + <<@experimenter::32, @nxast::16, 0::size(6)-unit(8), actions_bin::bytes>> + ) end def read(<<@experimenter::32, @nxast::16, 0::size(6)-unit(8), actions_bin::bytes>>) do diff --git a/lib/openflow/actions/nx_conjunction.ex b/lib/openflow/actions/nx_conjunction.ex index be33f2a..0760ecb 100644 --- a/lib/openflow/actions/nx_conjunction.ex +++ b/lib/openflow/actions/nx_conjunction.ex @@ -9,18 +9,27 @@ defmodule Openflow.Action.NxConjunction do @nxast 34 alias __MODULE__ + alias Openflow.Action.Experimenter + + def new(options \\ []) do + n_clauses = options[:n_clauses] || raise "n_clauses must be specified" + n_clauses >= 2 || raise "n_clauses must be greater than 1" - def new(options) do %NxConjunction{ - clause: options[:clause] || 0, - n_clauses: options[:n_clauses] || 0, + clause: (options[:clause] || 0) + 1, + n_clauses: n_clauses, id: options[:id] || 0 } end def to_binary(%NxConjunction{clause: clause, n_clauses: n_clauses, id: id}) do - exp_body = <<@experimenter::32, @nxast::16, clause::8, n_clauses::8, id::32>> - <<0xFFFF::16, 16::16, exp_body::bytes>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + clause::8, + n_clauses::8, + id::32 + >>) end def read(<<@experimenter::32, @nxast::16, clause::8, n_clauses::8, id::32>>) do diff --git a/lib/openflow/actions/nx_conntrack.ex b/lib/openflow/actions/nx_conntrack.ex index 7844221..bedee53 100644 --- a/lib/openflow/actions/nx_conntrack.ex +++ b/lib/openflow/actions/nx_conntrack.ex @@ -16,6 +16,7 @@ defmodule Openflow.Action.NxConntrack do @nxast 35 alias __MODULE__ + alias Openflow.Action.Experimenter def new(options \\ []) do %NxConntrack{ @@ -30,36 +31,21 @@ defmodule Openflow.Action.NxConntrack do } end - def to_binary(%NxConntrack{ - flags: flags, - zone_src: zone_src, - zone_offset: zone_ofs, - zone_n_bits: zone_n_bits, - zone_imm: zone_imm, - recirc_table: recirc_table, - alg: alg, - exec: exec - }) do - flags_int = Openflow.Enums.flags_to_int(flags, :nx_conntrack_flags) + def to_binary(%NxConntrack{} = ct) do + flags_int = Openflow.Enums.flags_to_int(ct.flags, :nx_conntrack_flags) + ct_context_bin = ct_context_binary(ct) + exec_bin = Openflow.Action.to_binary(ct.exec) - {src_bin, ofs_nbits} = - if not is_nil(zone_src) do - zone_src_bin = Openflow.Match.codec_header(zone_src) - {zone_src_bin, zone_ofs <<< 6 ||| zone_n_bits - 1} - else - {<<0::32>>, zone_imm} - end - - exec_bin = Openflow.Action.to_binary(exec) - - exp_body = - <<@experimenter::32, @nxast::16, flags_int::16, src_bin::bytes, ofs_nbits::16, - recirc_table::8, 0::size(3)-unit(8), alg::16, exec_bin::bytes>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + flags_int::16, + ct_context_bin::bytes, + ct.recirc_table::8, + 0::size(3)-unit(8), + ct.alg::16, + exec_bin::bytes + >>) end def read( @@ -87,4 +73,15 @@ defmodule Openflow.Action.NxConntrack do %{ct | zone_src: zone_src, zone_offset: ofs, zone_n_bits: n_bits + 1} end end + + # private functions + + defp ct_context_binary(%NxConntrack{zone_src: nil} = ct), + do: <<0::32, ct.zone_imm::16>> + + defp ct_context_binary(%NxConntrack{} = ct) do + zone_src_bin = Openflow.Match.codec_header(ct.zone_src) + ofs_nbits = ct.zone_offset <<< 6 ||| ct.zone_n_bits - 1 + <> + end end diff --git a/lib/openflow/actions/nx_controller.ex b/lib/openflow/actions/nx_controller.ex index 2f2d1fc..0086d22 100644 --- a/lib/openflow/actions/nx_controller.ex +++ b/lib/openflow/actions/nx_controller.ex @@ -9,8 +9,9 @@ defmodule Openflow.Action.NxController do @nxast 20 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do + def new(options \\ []) do %NxController{ max_len: options[:max_len] || :no_buffer, id: options[:id] || 0, @@ -18,14 +19,18 @@ defmodule Openflow.Action.NxController do } end - def to_binary(%NxController{max_len: max_len, id: controller_id, reason: reason}) do - max_len_int = Openflow.Utils.get_enum(max_len, :controller_max_len) - reason_int = Openflow.Enums.to_int(reason, :packet_in_reason) + def to_binary(%NxController{} = controller) do + max_len_int = Openflow.Utils.get_enum(controller.max_len, :controller_max_len) + reason_int = Openflow.Enums.to_int(controller.reason, :packet_in_reason) - exp_body = - <<@experimenter::32, @nxast::16, max_len_int::16, controller_id::16, reason_int::8, 0::8>> - - <<0xFFFF::16, 16::16, exp_body::bytes>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + max_len_int::16, + controller.id::16, + reason_int::8, + 0::8 + >>) end def read( diff --git a/lib/openflow/actions/nx_controller2.ex b/lib/openflow/actions/nx_controller2.ex index 7f20657..ef60a1e 100644 --- a/lib/openflow/actions/nx_controller2.ex +++ b/lib/openflow/actions/nx_controller2.ex @@ -23,8 +23,9 @@ defmodule Openflow.Action.NxController2 do @nx_ctlr_no_meter 0 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do + def new(options \\ []) do %NxController2{ max_len: options[:max_len] || :no_buffer, id: options[:id] || 0, @@ -36,14 +37,14 @@ defmodule Openflow.Action.NxController2 do end def to_binary(%NxController2{} = ctl) do - ext_header = <<@experimenter::32, @nxast::16, 0::size(6)-unit(8)>> - prop_keys = get_prop_key(ctl) - props_bin = encode_prop("", prop_keys, ctl) - exp_body = <> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes>> + props_bin = encode_props(ctl) + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + 0::size(6)-unit(8), + props_bin::bytes + >>) end def read(<<@experimenter::32, @nxast::16, 0::size(6)-unit(8), body::bytes>>) do @@ -53,101 +54,144 @@ defmodule Openflow.Action.NxController2 do # private functions - defp get_prop_key(ctl) do + defp encode_props(ctl) do ctl |> Map.from_struct() - |> Enum.map(fn {k, v} -> if(not is_nil(v), do: k, else: nil) end) - |> Enum.filter(fn v -> not is_nil(v) end) + |> Enum.reduce(<<>>, &encode_prop/2) end - defp encode_prop(acc, [], _ctl), do: acc + defp encode_prop({:max_len, value}, acc) + when value != :no_buffer or value < 0xFFFF do + pad_length = 2 + prop_length = @prop_header_size + 2 + pad_length + max_len_int = Openflow.Utils.get_enum(value, :controller_max_len) - defp encode_prop(acc, [prop | rest], ctl) do - value = Map.get(ctl, prop) + << + acc::bytes, + @prop_max_len::16, + prop_length::16, + max_len_int::16, + 0::size(pad_length)-unit(8) + >> + end - prop_bin = - cond do - prop == :max_len and (value != :no_buffer or value < 0xFFFF) -> - padding_length = 2 - prop_length = @prop_header_size + 2 + padding_length - max_len_int = Openflow.Utils.get_enum(value, :controller_max_len) - <<@prop_max_len::16, prop_length::16, max_len_int::16, 0::size(padding_length)-unit(8)>> + defp encode_prop({:id, value}, acc) do + pad_length = 2 + prop_length = @prop_header_size + 2 + pad_length - prop == :id -> - padding_length = 2 - prop_length = @prop_header_size + 2 + padding_length - <<@prop_ctl_id::16, prop_length::16, value::16, 0::size(padding_length)-unit(8)>> + << + acc::bytes, + @prop_ctl_id::16, + prop_length::16, + value::16, + 0::size(pad_length)-unit(8) + >> + end - prop == :reason and value != :action -> - padding_length = 3 - prop_length = @prop_header_size + 1 + padding_length - reason_int = Openflow.Utils.get_enum(value, :packet_in_reason) - <<@prop_reason::16, prop_length::16, reason_int::8, 0::size(padding_length)-unit(8)>> + defp encode_prop({:reason, reason}, acc) + when reason != :action do + padding_length = 3 + prop_length = @prop_header_size + 1 + padding_length + reason_int = Openflow.Utils.get_enum(reason, :packet_in_reason) - prop == :userdata and byte_size(value) > 0 -> - prop_length = @prop_header_size + byte_size(value) - padding_length = Openflow.Utils.padding(prop_length, 8) - <<@prop_userdata::16, prop_length::16, value::bytes, 0::size(padding_length)-unit(8)>> + << + acc::bytes, + @prop_reason::16, + prop_length::16, + reason_int::8, + 0::size(padding_length)-unit(8) + >> + end - prop == :pause and value == true -> - padding_length = 4 - prop_length = @prop_header_size + padding_length - <<@prop_pause::16, prop_length::16, 0::size(padding_length)-unit(8)>> + defp encode_prop({:userdata, value}, acc) + when byte_size(value) > 0 do + prop_length = @prop_header_size + byte_size(value) + padding_length = Openflow.Utils.padding(prop_length, 8) - prop == :meter_id and value != @nx_ctlr_no_meter -> - prop_length = @prop_header_size + 4 - <<@prop_meter_id::16, prop_length::16, value::32>> + << + acc::bytes, + @prop_userdata::16, + prop_length::16, + value::bytes, + 0::size(padding_length)-unit(8) + >> + end - true -> - "" - end + defp encode_prop({:pause, true}, acc) do + padding_length = 4 + prop_length = @prop_header_size + padding_length - encode_prop(<>, rest, ctl) + << + acc::bytes, + @prop_pause::16, + prop_length::16, + 0::size(padding_length)-unit(8) + >> + end + + defp encode_prop({:meter_id, value}, acc) + when value != @nx_ctlr_no_meter do + prop_length = @prop_header_size + 4 + + << + acc::bytes, + @prop_meter_id::16, + prop_length::16, + value::32 + >> + end + + defp encode_prop(_, acc) do + acc end defp decode_prop(ctl, ""), do: ctl - defp decode_prop(ctl, <> = bin) do - prop_type = Openflow.Enums.to_atom(prop_type_int, :nx_action_controller2_prop_type) + defp decode_prop( + ctl, + << + @prop_max_len::16, + _prop_length::16, + max_len_int::16, + _::size(2)-unit(8), + rest::bytes + >> + ) do + max_len = Openflow.Utils.get_enum(max_len_int, :controller_max_len) + decode_prop(%{ctl | max_len: max_len}, rest) + end - case prop_type do - :max_len -> - <<@prop_max_len::16, _prop_length::16, max_len_int::16, _::size(2)-unit(8), rest::bytes>> = - bin + defp decode_prop( + ctl, + <<@prop_reason::16, _prop_length::16, reason_int::8, _::size(3)-unit(8), rest::bytes>> + ) do + reason = Openflow.Utils.get_enum(reason_int, :packet_in_reason) + decode_prop(%{ctl | reason: reason}, rest) + end - max_len = Openflow.Utils.get_enum(max_len_int, :controller_max_len) - decode_prop(struct(ctl, %{max_len: max_len}), rest) + defp decode_prop( + ctl, + <<@prop_ctl_id::16, _prop_length::16, controller_id::16, _::size(2)-unit(8), + rest::bytes>> + ) do + decode_prop(%{ctl | id: controller_id}, rest) + end - :controller_id -> - <<@prop_ctl_id::16, _prop_length::16, controller_id::16, _::size(2)-unit(8), rest::bytes>> = - bin + defp decode_prop( + ctl, + <<@prop_userdata::16, prop_length::16, remains::bytes>> + ) do + userdata_len = prop_length - 4 + padding_length = Openflow.Utils.padding(prop_length, 8) + <> = remains + decode_prop(%{ctl | userdata: userdata}, rest) + end - decode_prop(struct(ctl, %{controller_id: controller_id}), rest) + defp decode_prop(ctl, <<@prop_pause::16, _::16, 0::size(4)-unit(8), rest::bytes>>) do + decode_prop(%{ctl | pause: true}, rest) + end - :reason -> - <<@prop_reason::16, _prop_length::16, reason_int::8, _::size(3)-unit(8), rest::bytes>> = - bin - - reason = Openflow.Utils.get_enum(reason_int, :packet_in_reason) - decode_prop(struct(ctl, %{reason: reason}), rest) - - :userdata -> - <<@prop_userdata::16, prop_length::16, remains::bytes>> = bin - userdata_len = prop_length - 4 - padding_length = Openflow.Utils.padding(prop_length, 8) - - <> = - remains - - decode_prop(struct(ctl, %{userdata: userdata}), rest) - - :pause -> - <<@prop_pause::16, _::16, 0::size(4)-unit(8), rest::bytes>> = bin - decode_prop(struct(ctl, %{pause: true}), rest) - - :meter_id -> - <<@prop_meter_id::16, _::16, meter_id::32, rest::bytes>> = bin - decode_prop(struct(ctl, %{meter_id: meter_id}), rest) - end + defp decode_prop(ctl, <<@prop_meter_id::16, _::16, meter_id::32, rest::bytes>>) do + decode_prop(%{ctl | meter_id: meter_id}, rest) end end diff --git a/lib/openflow/actions/nx_ct_clear.ex b/lib/openflow/actions/nx_ct_clear.ex index f58d3b3..84afeaa 100644 --- a/lib/openflow/actions/nx_ct_clear.ex +++ b/lib/openflow/actions/nx_ct_clear.ex @@ -5,14 +5,19 @@ defmodule Openflow.Action.NxCtClear do @nxast 43 alias __MODULE__ + alias Openflow.Action.Experimenter def new do %NxCtClear{} end def to_binary(%NxCtClear{}) do - exp_body = <<@experimenter::32, @nxast::16, 0::16, 0::size(4)-unit(8)>> - <<0xFFFF::16, 16::16, exp_body::bytes>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + 0::16, + 0::size(4)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, _::16, _::size(4)-unit(8)>>) do diff --git a/lib/openflow/actions/nx_dec_mpls_ttl.ex b/lib/openflow/actions/nx_dec_mpls_ttl.ex deleted file mode 100644 index 6b5744d..0000000 --- a/lib/openflow/actions/nx_dec_mpls_ttl.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule Openflow.Action.NxDecMplsTtl do - defstruct([]) - - @experimenter 0x00002320 - @nxast 26 - - alias __MODULE__ - - def new do - %NxDecMplsTtl{} - end - - def to_binary(%NxDecMplsTtl{}) do - exp_body = <<@experimenter::32, @nxast::16, 0::size(6)-unit(8)>> - <<0xFFFF::16, 16::16, exp_body::bytes>> - end - - def read(<<@experimenter::32, @nxast::16, _::size(6)-unit(8)>>) do - %NxDecMplsTtl{} - end -end diff --git a/lib/openflow/actions/nx_dec_ttl.ex b/lib/openflow/actions/nx_dec_ttl.ex index de6b088..f077f4c 100644 --- a/lib/openflow/actions/nx_dec_ttl.ex +++ b/lib/openflow/actions/nx_dec_ttl.ex @@ -5,14 +5,18 @@ defmodule Openflow.Action.NxDecTtl do @nxast 18 alias __MODULE__ + alias Openflow.Action.Experimenter def new do %NxDecTtl{} end def to_binary(%NxDecTtl{}) do - exp_body = <<@experimenter::32, @nxast::16, 0::size(6)-unit(8)>> - <<0xFFFF::16, 16::16, exp_body::bytes>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + 0::size(6)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, _::16, _::size(4)-unit(8)>>) do diff --git a/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex b/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex index 729b705..6cf6107 100644 --- a/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex +++ b/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex @@ -5,24 +5,23 @@ defmodule Openflow.Action.NxDecTtlCntIds do @nxast 21 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(ids) do + def new(ids \\ []) do %NxDecTtlCntIds{ids: ids} end def to_binary(%NxDecTtlCntIds{ids: ids}) do n_controllers = length(ids) - ids_bin = Enum.join(for(id <- ids, do: <>), "") - padding = Openflow.Utils.padding(n_controllers, 8) + ids_bin = Enum.reduce(ids, <<>>, fn id, acc -> <> end) - exp_body = - <<@experimenter::32, @nxast::16, n_controllers::16, 0::size(4)-unit(8), ids_bin::bytes, - 0::size(padding)-unit(8)>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + n_controllers::16, + 0::size(4)-unit(8), + ids_bin::bytes + >>) end def read(<<@experimenter::32, @nxast::16, n_controllers::16, body::bitstring>>) do diff --git a/lib/openflow/actions/nx_exit.ex b/lib/openflow/actions/nx_exit.ex index cc9786b..3c880c1 100644 --- a/lib/openflow/actions/nx_exit.ex +++ b/lib/openflow/actions/nx_exit.ex @@ -5,17 +5,17 @@ defmodule Openflow.Action.NxExit do @nxast 17 alias __MODULE__ + alias Openflow.Action.Experimenter def new do %NxExit{} end def to_binary(%NxExit{}) do - exp_body = <<@experimenter::32, @nxast::16, 0::48>> - <<0xFFFF::16, 16::16, exp_body::bytes>> + Experimenter.pack_exp_header(<<@experimenter::32, @nxast::16, 0::48>>) end - def read(<<@experimenter::32, @nxast::16, 0::48>>) do + def read(<<@experimenter::32, @nxast::16, 0::48, _::bytes>>) do %NxExit{} end end diff --git a/lib/openflow/actions/nx_fin_timeout.ex b/lib/openflow/actions/nx_fin_timeout.ex index 8f8e005..bd3e7ad 100644 --- a/lib/openflow/actions/nx_fin_timeout.ex +++ b/lib/openflow/actions/nx_fin_timeout.ex @@ -8,17 +8,22 @@ defmodule Openflow.Action.NxFinTimeout do @nxast 19 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do + def new(options \\ []) do %NxFinTimeout{ idle_timeout: options[:idle_timeout] || 0, hard_timeout: options[:hard_timeout] || 0 } end - def to_binary(%NxFinTimeout{idle_timeout: fin_idle, hard_timeout: fin_hard}) do - exp_body = <<@experimenter::32, @nxast::16, fin_idle::16, fin_hard::16>> - <<0xFFFF::16, 16::16, exp_body::bytes, 0::size(2)-unit(8)>> + def to_binary(%NxFinTimeout{} = fin_timeout) do + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + fin_timeout.idle_timeout::16, + fin_timeout.hard_timeout::16 + >>) end def read(<<@experimenter::32, @nxast::16, fin_idle::16, fin_hard::16, _::size(2)-unit(8)>>) do diff --git a/lib/openflow/actions/nx_learn.ex b/lib/openflow/actions/nx_learn.ex index 04b6cf3..5ac243c 100644 --- a/lib/openflow/actions/nx_learn.ex +++ b/lib/openflow/actions/nx_learn.ex @@ -15,6 +15,7 @@ defmodule Openflow.Action.NxLearn do @nxast 16 alias __MODULE__ + alias Openflow.Action.Experimenter def new(options) do %NxLearn{ @@ -30,28 +31,24 @@ defmodule Openflow.Action.NxLearn do } end - def to_binary(%NxLearn{ - idle_timeout: idle, - hard_timeout: hard, - priority: prio, - cookie: cookie, - flags: flags, - table_id: table_id, - fin_idle_timeout: fin_idle, - fin_hard_timeout: fin_hard, - flow_specs: flow_specs - }) do - flags_int = Openflow.Enums.flags_to_int(flags, :nx_learn_flag) - flow_specs_bin = Openflow.Action.NxFlowSpec.to_binary(flow_specs) + def to_binary(%NxLearn{} = learn) do + learn_flags_int = Openflow.Enums.flags_to_int(learn.flags, :nx_learn_flag) + flow_specs_bin = Openflow.Action.NxFlowSpec.to_binary(learn.flow_specs) - exp_body = - <<@experimenter::32, @nxast::16, idle::16, hard::16, prio::16, cookie::64, flags_int::16, - table_id::8, 0::size(1)-unit(8), fin_idle::16, fin_hard::16, flow_specs_bin::bitstring>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + learn.idle_timeout::16, + learn.hard_timeout::16, + learn.priority::16, + learn.cookie::64, + learn_flags_int::16, + learn.table_id::8, + 0::8, + learn.fin_idle_timeout::16, + learn.fin_hard_timeout::16, + flow_specs_bin::bitstring + >>) end def read(<<@experimenter::32, @nxast::16, body::bitstring>>) do diff --git a/lib/openflow/actions/nx_learn2.ex b/lib/openflow/actions/nx_learn2.ex index ea3a49d..f576c63 100644 --- a/lib/openflow/actions/nx_learn2.ex +++ b/lib/openflow/actions/nx_learn2.ex @@ -18,6 +18,7 @@ defmodule Openflow.Action.NxLearn2 do @nxast 45 alias __MODULE__ + alias Openflow.Action.Experimenter def new(options) do %NxLearn2{ @@ -36,40 +37,33 @@ defmodule Openflow.Action.NxLearn2 do } end - def to_binary(%NxLearn2{ - idle_timeout: idle, - hard_timeout: hard, - priority: prio, - cookie: cookie, - flags: flags, - table_id: table_id, - fin_idle_timeout: fin_idle, - fin_hard_timeout: fin_hard, - limit: limit, - result_dst_offset: result_dst_ofs, - result_dst: result_dst, - flow_specs: flow_specs - }) do - flags_int = Openflow.Enums.flags_to_int(flags, :nx_learn_flag) + def to_binary(%NxLearn2{} = learn) do + learn_flags_int = Openflow.Enums.flags_to_int(learn.flags, :nx_learn_flag) + learn_flow_specs_bin = Openflow.Action.NxFlowSpec.to_binary(learn.flow_specs) - result_dst_bin = - if :write_result in flags do - Openflow.Match.codec_header(result_dst) - else - "" - end + learn_result_dst_bin = + if :write_result in learn.flags, + do: Openflow.Match.codec_header(learn.result_dst), + else: <<>> - flow_specs_bin = Openflow.Action.NxFlowSpec.to_binary(flow_specs) - - exp_body = - <<@experimenter::32, @nxast::16, idle::16, hard::16, prio::16, cookie::64, flags_int::16, - table_id::8, 0::size(1)-unit(8), fin_idle::16, fin_hard::16, limit::32, - result_dst_ofs::16, 0::size(2)-unit(8), result_dst_bin::bytes, flow_specs_bin::bitstring>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + learn.idle_timeout::16, + learn.hard_timeout::16, + learn.priority::16, + learn.cookie::64, + learn_flags_int::16, + learn.table_id::8, + 0::size(1)-unit(8), + learn.fin_idle_timeout::16, + learn.fin_hard_timeout::16, + learn.limit::32, + learn.result_dst_offset::16, + 0::size(2)-unit(8), + learn_result_dst_bin::bytes, + learn_flow_specs_bin::bitstring + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_multipath.ex b/lib/openflow/actions/nx_multipath.ex index 72975e0..b058250 100644 --- a/lib/openflow/actions/nx_multipath.ex +++ b/lib/openflow/actions/nx_multipath.ex @@ -16,54 +16,43 @@ defmodule Openflow.Action.NxMultipath do @nxast 10 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - hash_field = Keyword.get(options, :hash_field, :eth_src) - basis = Keyword.get(options, :basis, 0) - alg = Keyword.get(options, :algorithm, :modulo_n) - max_link = Keyword.get(options, :max_link, 0) - arg = Keyword.get(options, :argument, 0) - dst_field = Keyword.get(options, :dst_field) + def new(options \\ []) do + dst_field = options[:dst_field] || raise "dst_field must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(dst_field) - n_bits = Keyword.get(options, :n_bits, default_n_bits) - ofs = Keyword.get(options, :offset, 0) %NxMultipath{ - hash_field: hash_field, - basis: basis, - algorithm: alg, - max_link: max_link, - offset: ofs, - n_bits: n_bits, - argument: arg, + hash_field: options[:hash_field] || :eth_src, + basis: options[:basis] || 0, + algorithm: options[:algorithm] || :modulo_n, + max_link: options[:max_link] || 0, + offset: options[:offset] || 0, + n_bits: options[:n_bits] || default_n_bits, + argument: options[:argument] || 0, dst_field: dst_field } end - def to_binary(%NxMultipath{ - hash_field: hash_field, - basis: basis, - algorithm: alg, - max_link: max_link, - argument: arg, - offset: ofs, - n_bits: n_bits, - dst_field: dst_field - }) do - hash_field_int = Openflow.Enums.to_int(hash_field, :nx_hash_fields) - alg_int = Openflow.Enums.to_int(alg, :nx_mp_algorithm) - dst_field_bin = Openflow.Match.codec_header(dst_field) - ofs_nbits = ofs <<< 6 ||| n_bits - 1 + def to_binary(%NxMultipath{} = multipath) do + hash_field_int = Openflow.Enums.to_int(multipath.hash_field, :nx_hash_fields) + alg_int = Openflow.Enums.to_int(multipath.algorithm, :nx_mp_algorithm) + dst_field_bin = Openflow.Match.codec_header(multipath.dst_field) + ofs_nbits = multipath.offset <<< 6 ||| multipath.n_bits - 1 - body = - <> - - exp_body = <<@experimenter::32, @nxast::16, body::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + hash_field_int::16, + multipath.basis::16, + 0::size(2)-unit(8), + alg_int::16, + multipath.max_link::16, + multipath.argument::32, + 0::size(2)-unit(8), + ofs_nbits::16, + dst_field_bin::4-bytes + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_nat.ex b/lib/openflow/actions/nx_nat.ex index 921d5f1..0c468e4 100644 --- a/lib/openflow/actions/nx_nat.ex +++ b/lib/openflow/actions/nx_nat.ex @@ -13,6 +13,7 @@ defmodule Openflow.Action.NxNat do @nxast 36 alias __MODULE__ + alias Openflow.Action.Experimenter def new(options \\ []) do flags = Keyword.get(options, :flags, []) @@ -46,14 +47,14 @@ defmodule Openflow.Action.NxNat do ranges_bin = encode_ranges("", range_flags, nat) range_flags_int = Openflow.Enums.flags_to_int(range_flags, :nx_nat_range) - exp_body = - <<@experimenter::32, @nxast::16, 0::size(2)-unit(8), flags_int::16, range_flags_int::16, - ranges_bin::bytes>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + 0::size(2)-unit(8), + flags_int::16, + range_flags_int::16, + ranges_bin::bytes + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_note.ex b/lib/openflow/actions/nx_note.ex index b96847d..d6ce09a 100644 --- a/lib/openflow/actions/nx_note.ex +++ b/lib/openflow/actions/nx_note.ex @@ -5,18 +5,14 @@ defmodule Openflow.Action.NxNote do @nxast 8 alias __MODULE__ + alias Openflow.Action.Experimenter def new(note) do %NxNote{note: note} end def to_binary(%NxNote{note: note}) do - padding = Openflow.Utils.padding(byte_size(note) + 2, 8) - exp_body = <<@experimenter::32, @nxast::16, note::bytes, 0::size(padding)-unit(8)>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<<@experimenter::32, @nxast::16, note::bytes>>) end def read(<<@experimenter::32, @nxast::16, note_bin::bytes>>) do diff --git a/lib/openflow/actions/nx_output_reg.ex b/lib/openflow/actions/nx_output_reg.ex index 852358a..d0d484b 100644 --- a/lib/openflow/actions/nx_output_reg.ex +++ b/lib/openflow/actions/nx_output_reg.ex @@ -12,26 +12,33 @@ defmodule Openflow.Action.NxOutputReg do @nxast 15 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - src_field = Keyword.get(options, :src_field) + def new(options \\ []) do + src_field = options[:src_field] || raise "src_field must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(src_field) - n_bits = Keyword.get(options, :n_bits, default_n_bits) - ofs = Keyword.get(options, :offset, 0) - max_len = Keyword.get(options, :max_len, :no_buffer) - %NxOutputReg{n_bits: n_bits, offset: ofs, src_field: src_field, max_len: max_len} + + %NxOutputReg{ + n_bits: options[:n_bits] || default_n_bits, + offset: options[:offset] || 0, + src_field: src_field, + max_len: options[:max_len] || :no_buffer + } end - def to_binary(%NxOutputReg{n_bits: n_bits, offset: ofs, src_field: src_field, max_len: max_len}) do - src_field_bin = Openflow.Match.codec_header(src_field) - ofs_nbits = ofs <<< 6 ||| n_bits - 1 - max_len = Openflow.Utils.get_enum(max_len, :controller_max_len) - body = <> - exp_body = <<@experimenter::32, @nxast::16, body::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + def to_binary(%NxOutputReg{} = output_reg) do + src_field_bin = Openflow.Match.codec_header(output_reg.src_field) + ofs_nbits = output_reg.offset <<< 6 ||| output_reg.n_bits - 1 + max_len = Openflow.Utils.get_enum(output_reg.max_len, :controller_max_len) + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + ofs_nbits::16, + src_field_bin::4-bytes, + max_len::16, + 0::size(6)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_output_reg2.ex b/lib/openflow/actions/nx_output_reg2.ex index e254cf3..d430190 100644 --- a/lib/openflow/actions/nx_output_reg2.ex +++ b/lib/openflow/actions/nx_output_reg2.ex @@ -12,27 +12,38 @@ defmodule Openflow.Action.NxOutputReg2 do @nxast 32 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - src_field = Keyword.get(options, :src_field) + def new(options \\ []) do + src_field = options[:src_field] || raise "src_field must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(src_field) - n_bits = Keyword.get(options, :n_bits, default_n_bits) - ofs = Keyword.get(options, :offset, 0) - max_len = Keyword.get(options, :max_len, :no_buffer) - %NxOutputReg2{n_bits: n_bits, offset: ofs, src_field: src_field, max_len: max_len} + + %NxOutputReg2{ + n_bits: options[:n_bits] || default_n_bits, + offset: options[:offset] || 0, + src_field: src_field, + max_len: options[:max_len] || :no_buffer + } end - def to_binary(%NxOutputReg2{n_bits: n_bits, offset: ofs, src_field: src_field, max_len: max_len}) do - src_field_bin = Openflow.Match.codec_header(src_field) - ofs_nbits = ofs <<< 6 ||| n_bits - 1 - max_len = Openflow.Utils.get_enum(max_len, :controller_max_len) - padding = Openflow.Utils.padding(byte_size(src_field_bin), 10) - body = <> - exp_body = <<@experimenter::32, @nxast::16, body::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + def to_binary(%NxOutputReg2{} = output_reg) do + src_field_bin = Openflow.Match.codec_header(output_reg.src_field) + ofs_nbits = output_reg.offset <<< 6 ||| output_reg.n_bits - 1 + max_len = Openflow.Utils.get_enum(output_reg.max_len, :controller_max_len) + + padding = + src_field_bin + |> byte_size() + |> Openflow.Utils.padding(10) + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + ofs_nbits::16, + max_len::16, + src_field_bin::bytes, + 0::size(padding)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_output_trunc.ex b/lib/openflow/actions/nx_output_trunc.ex index 98b3c6e..d5b1c56 100644 --- a/lib/openflow/actions/nx_output_trunc.ex +++ b/lib/openflow/actions/nx_output_trunc.ex @@ -8,20 +8,27 @@ defmodule Openflow.Action.NxOutputTrunc do @nxast 39 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - port_no = Keyword.get(options, :port_number) - max_len = Keyword.get(options, :max_len) - %NxOutputTrunc{port_number: port_no, max_len: max_len} + def new(options \\ []) do + port_no = options[:port_no] || raise "port_no must be specified" + max_len = options[:max_len] || raise "max_len must be specified" + + %NxOutputTrunc{ + port_number: port_no, + max_len: max_len + } end def to_binary(%NxOutputTrunc{port_number: port_no, max_len: max_len}) do port_no_int = Openflow.Utils.get_enum(port_no, :openflow10_port_no) - exp_body = <<@experimenter::32, @nxast::16, port_no_int::16, max_len::32>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + port_no_int::16, + max_len::32 + >>) end def read(<<@experimenter::32, @nxast::16, port_no_int::16, max_len::32>>) do diff --git a/lib/openflow/actions/nx_pop_mpls.ex b/lib/openflow/actions/nx_pop_mpls.ex index f14f863..c01a44e 100644 --- a/lib/openflow/actions/nx_pop_mpls.ex +++ b/lib/openflow/actions/nx_pop_mpls.ex @@ -4,18 +4,22 @@ defmodule Openflow.Action.NxPopMpls do @experimenter 0x00002320 @nxast 24 - alias __MODULE__ + @eth_p_mpls_uc 0x8847 - def new(ethertype \\ 0x8847) do + alias __MODULE__ + alias Openflow.Action.Experimenter + + def new(ethertype \\ @eth_p_mpls_uc) do %NxPopMpls{ethertype: ethertype} end def to_binary(%NxPopMpls{ethertype: ethertype}) do - exp_body = <<@experimenter::32, @nxast::16, ethertype::16, 0::size(4)-unit(8)>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + ethertype::16, + 0::size(4)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, ethertype::16, _::size(4)-unit(8)>>) do diff --git a/lib/openflow/actions/nx_pop_queue.ex b/lib/openflow/actions/nx_pop_queue.ex deleted file mode 100644 index 4821cd3..0000000 --- a/lib/openflow/actions/nx_pop_queue.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule Openflow.Action.NxPopQueue do - defstruct([]) - - @experimenter 0x00002320 - @nxast 5 - - alias __MODULE__ - - def new do - %NxPopQueue{} - end - - def to_binary(%NxPopQueue{}) do - exp_body = <<@experimenter::32, @nxast::16, 0::48>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> - end - - def read(<<@experimenter::32, @nxast::16, 0::size(6)-unit(8)>>) do - %NxPopQueue{} - end -end diff --git a/lib/openflow/actions/nx_push_mpls.ex b/lib/openflow/actions/nx_push_mpls.ex index 4db52b0..8a12d9e 100644 --- a/lib/openflow/actions/nx_push_mpls.ex +++ b/lib/openflow/actions/nx_push_mpls.ex @@ -4,18 +4,22 @@ defmodule Openflow.Action.NxPushMpls do @experimenter 0x00002320 @nxast 23 - alias __MODULE__ + @eth_p_mpls_uc 0x8847 - def new(ethertype \\ 0x8847) do + alias __MODULE__ + alias Openflow.Action.Experimenter + + def new(ethertype \\ @eth_p_mpls_uc) do %NxPushMpls{ethertype: ethertype} end def to_binary(%NxPushMpls{ethertype: ethertype}) do - exp_body = <<@experimenter::32, @nxast::16, ethertype::16, 0::size(4)-unit(8)>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + ethertype::16, + 0::size(4)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, ethertype::16, _::size(4)-unit(8)>>) do diff --git a/lib/openflow/actions/nx_reg_load.ex b/lib/openflow/actions/nx_reg_load.ex index 1ee7da5..fbd4b22 100644 --- a/lib/openflow/actions/nx_reg_load.ex +++ b/lib/openflow/actions/nx_reg_load.ex @@ -12,28 +12,37 @@ defmodule Openflow.Action.NxRegLoad do @nxast 7 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - dst_field = Keyword.get(options, :dst_field) + def new(options \\ []) do + dst_field = options[:dst_field] || raise "dst_field must be specified" + value = options[:value] || raise "value must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(dst_field) - n_bits = Keyword.get(options, :n_bits, default_n_bits) - ofs = Keyword.get(options, :offset, 0) - value = Keyword.get(options, :value) - %NxRegLoad{n_bits: n_bits, offset: ofs, dst_field: dst_field, value: value} + + %NxRegLoad{ + n_bits: options[:n_bits] || default_n_bits, + offset: options[:offset] || 0, + dst_field: dst_field, + value: value + } end - def to_binary(%NxRegLoad{n_bits: n_bits, offset: ofs, dst_field: dst_field, value: value}) do - dst_field_bin = Openflow.Match.codec_header(dst_field) - value_bin0 = Openflow.Match.Field.codec(value, dst_field) - tmp_value = :binary.decode_unsigned(value_bin0, :big) - value_bin = <> - ofs_nbits = ofs <<< 6 ||| n_bits - 1 - body = <> - exp_body = <<@experimenter::32, @nxast::16, body::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + def to_binary(%NxRegLoad{} = load) do + ofs_nbits = load.offset <<< 6 ||| load.n_bits - 1 + dst_field_bin = Openflow.Match.codec_header(load.dst_field) + + value_int = + load.value + |> Openflow.Match.Field.codec(load.dst_field) + |> :binary.decode_unsigned(:big) + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + ofs_nbits::16, + dst_field_bin::4-bytes, + value_int::size(8)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_reg_load2.ex b/lib/openflow/actions/nx_reg_load2.ex index 0c1510e..fd98dd0 100644 --- a/lib/openflow/actions/nx_reg_load2.ex +++ b/lib/openflow/actions/nx_reg_load2.ex @@ -1,44 +1,38 @@ defmodule Openflow.Action.NxRegLoad2 do - defstruct( - dst_field: nil, - value: nil - ) + defstruct(field: nil) @experimenter 0x00002320 @nxast 33 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - dst_field = Keyword.get(options, :dst_field) - value = Keyword.get(options, :value) - %NxRegLoad2{dst_field: dst_field, value: value} + def new([{_field, _value}] = field) do + %NxRegLoad2{field: field} end - def to_binary(%NxRegLoad2{dst_field: dst_field, value: value}) do + def to_binary(%NxRegLoad2{field: field}) do match_bin = - [{dst_field, value}] + field |> Openflow.Match.new() |> Openflow.Match.to_binary() - <<1::16, _length::16, padded_field::bytes>> = match_bin - patial_len = 4 + 4 + 2 + 6 + byte_size(padded_field) - padding = Openflow.Utils.padding(patial_len, 8) + <<1::16, length::16, padded_field::bytes>> = match_bin + field_len = length - 4 + <> = padded_field - exp_body = - <<@experimenter::32, @nxast::16, 0::48, padded_field::bytes, 0::size(padding)-unit(8)>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + field_bin::bytes + >>) end - def read(<<@experimenter::32, @nxast::16, _::48, match_field_bin::bytes>>) do + def read(<<@experimenter::32, @nxast::16, match_field_bin::bytes>>) do <<_class::16, _field::7, _hm::1, flen::8, _rest::bytes>> = match_field_bin match_len = 4 + 4 + flen - match_bin = <<1::16, match_len::16, match_field_bin::bytes, 0::size(4)-unit(8)>> - {[{dst_field, value} | _], _rest} = Openflow.Match.read(match_bin) - %NxRegLoad2{dst_field: dst_field, value: value} + match_bin = <<1::16, match_len::16, match_field_bin::bytes>> + {[field | _], _rest} = Openflow.Match.read(match_bin) + %NxRegLoad2{field: [field]} end end diff --git a/lib/openflow/actions/nx_reg_move.ex b/lib/openflow/actions/nx_reg_move.ex index 309fd38..fc8071f 100644 --- a/lib/openflow/actions/nx_reg_move.ex +++ b/lib/openflow/actions/nx_reg_move.ex @@ -11,42 +11,35 @@ defmodule Openflow.Action.NxRegMove do @nxast 6 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - src_field = Keyword.get(options, :src_field) - dst_field = Keyword.get(options, :dst_field) + def new(options \\ []) do + src_field = options[:src_field] || raise "src_field must be specified" + dst_field = options[:dst_field] || raise "dst_field must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(dst_field) - n_bits = Keyword.get(options, :n_bits, default_n_bits) - src_ofs = Keyword.get(options, :src_offset, 0) - dst_ofs = Keyword.get(options, :dst_offset, 0) %NxRegMove{ - n_bits: n_bits, - src_offset: src_ofs, - dst_offset: dst_ofs, + n_bits: options[:n_bits] || default_n_bits, + src_offset: options[:src_offset] || 0, + dst_offset: options[:dst_offset] || 0, src_field: src_field, dst_field: dst_field } end - def to_binary(%NxRegMove{ - n_bits: n_bits, - src_offset: src_ofs, - dst_offset: dst_ofs, - src_field: src_field, - dst_field: dst_field - }) do - src_field_bin = Openflow.Match.codec_header(src_field) - dst_field_bin = Openflow.Match.codec_header(dst_field) + def to_binary(%NxRegMove{} = move) do + src_field_bin = Openflow.Match.codec_header(move.src_field) + dst_field_bin = Openflow.Match.codec_header(move.dst_field) - body = - <> - - exp_body = <<@experimenter::32, @nxast::16, body::bytes>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + move.n_bits::16, + move.src_offset::16, + move.dst_offset::16, + src_field_bin::4-bytes, + dst_field_bin::4-bytes + >>) end def read(<<@experimenter::32, @nxast::16, body::bytes>>) do diff --git a/lib/openflow/actions/nx_resubmit.ex b/lib/openflow/actions/nx_resubmit.ex index 9ed1623..d0dbd11 100644 --- a/lib/openflow/actions/nx_resubmit.ex +++ b/lib/openflow/actions/nx_resubmit.ex @@ -5,6 +5,7 @@ defmodule Openflow.Action.NxResubmit do @nxast 1 alias __MODULE__ + alias Openflow.Action.Experimenter def new(in_port \\ :in_port) do %NxResubmit{in_port: in_port} @@ -12,11 +13,13 @@ defmodule Openflow.Action.NxResubmit do def to_binary(%NxResubmit{in_port: in_port}) do in_port_int = Openflow.Utils.get_enum(in_port, :openflow10_port_no) - exp_body = <<@experimenter::32, @nxast::16, in_port_int::16, 0::size(4)-unit(8)>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + in_port_int::16, + 0::size(4)-unit(8) + >>) end def read(<<@experimenter::32, @nxast::16, in_port_int::16, _::size(4)-unit(8)>>) do diff --git a/lib/openflow/actions/nx_resubmit_table.ex b/lib/openflow/actions/nx_resubmit_table.ex index 04bbba8..1553a71 100644 --- a/lib/openflow/actions/nx_resubmit_table.ex +++ b/lib/openflow/actions/nx_resubmit_table.ex @@ -5,25 +5,31 @@ defmodule Openflow.Action.NxResubmitTable do @nxast 14 alias __MODULE__ + alias Openflow.Action.Experimenter + + def new(options \\ []) def new(table_id) when is_atom(table_id) or is_integer(table_id) do new(table_id: table_id) end def new(options) do - in_port = Keyword.get(options, :in_port, :in_port) - table_id = Keyword.get(options, :table_id, :all) + in_port = options[:in_port] || :in_port + table_id = options[:table_id] || :all %NxResubmitTable{in_port: in_port, table_id: table_id} end - def to_binary(%NxResubmitTable{in_port: in_port, table_id: table_id}) do - in_port_int = Openflow.Utils.get_enum(in_port, :openflow10_port_no) - table_id_int = Openflow.Utils.get_enum(table_id, :table_id) - exp_body = <<@experimenter::32, @nxast::16, in_port_int::16, table_id_int::8, 0::24>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + def to_binary(%NxResubmitTable{} = resubmit_table) do + in_port_int = Openflow.Utils.get_enum(resubmit_table.in_port, :openflow10_port_no) + table_id_int = Openflow.Utils.get_enum(resubmit_table.table_id, :table_id) + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + in_port_int::16, + table_id_int::8, + 0::24 + >>) end def read( diff --git a/lib/openflow/actions/nx_resubmit_table_ct.ex b/lib/openflow/actions/nx_resubmit_table_ct.ex index 849640e..6eb8bc9 100644 --- a/lib/openflow/actions/nx_resubmit_table_ct.ex +++ b/lib/openflow/actions/nx_resubmit_table_ct.ex @@ -5,21 +5,31 @@ defmodule Openflow.Action.NxResubmitTableCt do @nxast 44 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - in_port = Keyword.get(options, :in_port, :in_port) - table_id = Keyword.get(options, :table_id, :all) + def new(options \\ []) + + def new(table_id) when is_atom(table_id) or is_integer(table_id) do + new(table_id: table_id) + end + + def new(options) when is_list(options) do + in_port = options[:in_port] || :in_port + table_id = options[:table_id] || :all %NxResubmitTableCt{in_port: in_port, table_id: table_id} end - def to_binary(%NxResubmitTableCt{in_port: in_port, table_id: table_id}) do - in_port_int = Openflow.Utils.get_enum(in_port, :openflow10_port_no) - table_id_int = Openflow.Utils.get_enum(table_id, :table_id) - exp_body = <<@experimenter::32, @nxast::16, in_port_int::16, table_id_int::8, 0::24>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + def to_binary(%NxResubmitTableCt{} = resubmit_table) do + in_port_int = Openflow.Utils.get_enum(resubmit_table.in_port, :openflow10_port_no) + table_id_int = Openflow.Utils.get_enum(resubmit_table.table_id, :table_id) + + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + in_port_int::16, + table_id_int::8, + 0::24 + >>) end def read( diff --git a/lib/openflow/actions/nx_sample.ex b/lib/openflow/actions/nx_sample.ex index 206c0ed..cc725ae 100644 --- a/lib/openflow/actions/nx_sample.ex +++ b/lib/openflow/actions/nx_sample.ex @@ -10,35 +10,26 @@ defmodule Openflow.Action.NxSample do @nxast 29 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - probability = Keyword.get(options, :probability, 0) - collector_set_id = Keyword.get(options, :collector_set_id, 0) - obs_domain_id = Keyword.get(options, :obs_domain_id, 0) - obs_point_id = Keyword.get(options, :obs_point_id, 0) - + def new(options \\ []) do %NxSample{ - probability: probability, - collector_set_id: collector_set_id, - obs_domain_id: obs_domain_id, - obs_point_id: obs_point_id + probability: options[:probability] || 0, + collector_set_id: options[:collector_set_id] || 0, + obs_domain_id: options[:obs_domain_id] || 0, + obs_point_id: options[:obs_point_id] || 0 } end - def to_binary(%NxSample{ - probability: probability, - collector_set_id: collector_set_id, - obs_domain_id: obs_domain_id, - obs_point_id: obs_point_id - }) do - exp_body = - <<@experimenter::32, @nxast::16, probability::16, collector_set_id::32, obs_domain_id::32, - obs_point_id::32>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + def to_binary(%NxSample{} = sample) do + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + sample.probability::16, + sample.collector_set_id::32, + sample.obs_domain_id::32, + sample.obs_point_id::32 + >>) end def read( diff --git a/lib/openflow/actions/nx_sample2.ex b/lib/openflow/actions/nx_sample2.ex index 271a3c6..f6ba206 100644 --- a/lib/openflow/actions/nx_sample2.ex +++ b/lib/openflow/actions/nx_sample2.ex @@ -11,44 +11,41 @@ defmodule Openflow.Action.NxSample2 do @nxast 38 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - probability = Keyword.get(options, :probability, 0) - collector_set_id = Keyword.get(options, :collector_set_id, 0) - obs_domain_id = Keyword.get(options, :obs_domain_id, 0) - obs_point_id = Keyword.get(options, :obs_point_id, 0) - sampling_port = Keyword.get(options, :sampling_port, 0) - + def new(options \\ []) do %NxSample2{ - probability: probability, - collector_set_id: collector_set_id, - obs_domain_id: obs_domain_id, - obs_point_id: obs_point_id, - sampling_port: sampling_port + probability: options[:probability] || 0, + collector_set_id: options[:collector_set_id] || 0, + obs_domain_id: options[:obs_domain_id] || 0, + obs_point_id: options[:obs_point_id] || 0, + sampling_port: options[:sampling_port] || 0 } end - def to_binary(%NxSample2{ - probability: probability, - collector_set_id: collector_set_id, - obs_domain_id: obs_domain_id, - obs_point_id: obs_point_id, - sampling_port: sampling_port - }) do - exp_body = - <<@experimenter::32, @nxast::16, probability::16, collector_set_id::32, obs_domain_id::32, - obs_point_id::32, sampling_port::16, 0::size(6)-unit(8)>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + def to_binary(%NxSample2{} = sample) do + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + sample.probability::16, + sample.collector_set_id::32, + sample.obs_domain_id::32, + sample.obs_point_id::32, + sample.sampling_port::16, + 0::size(6)-unit(8) + >>) end - def read( - <<@experimenter::32, @nxast::16, probability::16, collector_set_id::32, obs_domain_id::32, - obs_point_id::32, sampling_port::16, 0::size(6)-unit(8)>> - ) do + def read(<< + @experimenter::32, + @nxast::16, + probability::16, + collector_set_id::32, + obs_domain_id::32, + obs_point_id::32, + sampling_port::16, + _::size(6)-unit(8) + >>) do %NxSample2{ probability: probability, collector_set_id: collector_set_id, diff --git a/lib/openflow/actions/nx_sample3.ex b/lib/openflow/actions/nx_sample3.ex index bb1c531..5a01bb6 100644 --- a/lib/openflow/actions/nx_sample3.ex +++ b/lib/openflow/actions/nx_sample3.ex @@ -12,43 +12,33 @@ defmodule Openflow.Action.NxSample3 do @nxast 41 alias __MODULE__ + alias Openflow.Action.Experimenter - def new(options) do - probability = Keyword.get(options, :probability, 0) - collector_set_id = Keyword.get(options, :collector_set_id, 0) - obs_domain_id = Keyword.get(options, :obs_domain_id, 0) - obs_point_id = Keyword.get(options, :obs_point_id, 0) - sampling_port = Keyword.get(options, :sampling_port, 0) - direction = Keyword.get(options, :direction, :default) - + def new(options \\ []) do %NxSample3{ - probability: probability, - collector_set_id: collector_set_id, - obs_domain_id: obs_domain_id, - obs_point_id: obs_point_id, - sampling_port: sampling_port, - direction: direction + probability: options[:probability] || 0, + collector_set_id: options[:collector_set_id] || 0, + obs_domain_id: options[:obs_domain_id] || 0, + obs_point_id: options[:obs_point_id] || 0, + sampling_port: options[:sampling_port] || 0, + direction: options[:direction] || :default } end - def to_binary(%NxSample3{ - probability: probability, - collector_set_id: collector_set_id, - obs_domain_id: obs_domain_id, - obs_point_id: obs_point_id, - sampling_port: sampling_port, - direction: direction - }) do - direction_int = Openflow.Enums.to_int(direction, :nx_action_sample_direction) + def to_binary(%NxSample3{} = sample) do + sample_direction_int = Openflow.Enums.to_int(sample.direction, :nx_action_sample_direction) - exp_body = - <<@experimenter::32, @nxast::16, probability::16, collector_set_id::32, obs_domain_id::32, - obs_point_id::32, sampling_port::16, direction_int::8, 0::size(5)-unit(8)>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + sample.probability::16, + sample.collector_set_id::32, + sample.obs_domain_id::32, + sample.obs_point_id::32, + sample.sampling_port::16, + sample_direction_int::8, + 0::size(5)-unit(8) + >>) end def read( diff --git a/lib/openflow/actions/nx_set_mpls_label.ex b/lib/openflow/actions/nx_set_mpls_label.ex deleted file mode 100644 index 9fdcf04..0000000 --- a/lib/openflow/actions/nx_set_mpls_label.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule Openflow.Action.NxSetMplsLabel do - defstruct(label: 0) - - @experimenter 0x00002320 - @nxast 30 - - alias __MODULE__ - - def new(label) do - %NxSetMplsLabel{label: label} - end - - def to_binary(%NxSetMplsLabel{label: label}) do - exp_body = <<@experimenter::32, @nxast::16, 0::16, label::32>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> - end - - def read(<<@experimenter::32, @nxast::16, _::16, label::32>>) do - %NxSetMplsLabel{label: label} - end -end diff --git a/lib/openflow/actions/nx_set_mpls_tc.ex b/lib/openflow/actions/nx_set_mpls_tc.ex deleted file mode 100644 index 9392558..0000000 --- a/lib/openflow/actions/nx_set_mpls_tc.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule Openflow.Action.NxSetMplsTc do - defstruct(tc: 0) - - @experimenter 0x00002320 - @nxast 31 - - alias __MODULE__ - - def new(tc) do - %NxSetMplsTc{tc: tc} - end - - def to_binary(%NxSetMplsTc{tc: tc}) do - exp_body = <<@experimenter::32, @nxast::16, tc::8, 0::size(5)-unit(8)>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> - end - - def read(<<@experimenter::32, @nxast::16, tc::8, _::size(5)-unit(8)>>) do - %NxSetMplsTc{tc: tc} - end -end diff --git a/lib/openflow/actions/nx_set_mpls_ttl.ex b/lib/openflow/actions/nx_set_mpls_ttl.ex deleted file mode 100644 index cd932af..0000000 --- a/lib/openflow/actions/nx_set_mpls_ttl.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule Openflow.Action.NxSetMplsTtl do - defstruct(ttl: 0) - - @experimenter 0x00002320 - @nxast 25 - - alias __MODULE__ - - def new(ttl) do - %NxSetMplsTtl{ttl: ttl} - end - - def to_binary(%NxSetMplsTtl{ttl: ttl}) do - exp_body = <<@experimenter::32, @nxast::16, ttl::8, 0::size(5)-unit(8)>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> - end - - def read(<<@experimenter::32, @nxast::16, ttl::8, _::size(5)-unit(8)>>) do - %NxSetMplsTtl{ttl: ttl} - end -end diff --git a/lib/openflow/actions/nx_set_queue.ex b/lib/openflow/actions/nx_set_queue.ex deleted file mode 100644 index 845c494..0000000 --- a/lib/openflow/actions/nx_set_queue.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule Openflow.Action.NxSetQueue do - defstruct(queue_id: 0) - - @experimenter 0x00002320 - @nxast 4 - - alias __MODULE__ - - def new(queue_id) do - %NxSetQueue{queue_id: queue_id} - end - - def to_binary(%NxSetQueue{queue_id: queue_id}) do - exp_body = <<@experimenter::32, @nxast::16, 0::16, queue_id::32>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> - end - - def read(<<@experimenter::32, @nxast::16, 0::size(2)-unit(8), queue_id::32>>) do - %NxSetQueue{queue_id: queue_id} - end -end diff --git a/lib/openflow/actions/nx_set_tunnel.ex b/lib/openflow/actions/nx_set_tunnel.ex index 661114b..c7c6b59 100644 --- a/lib/openflow/actions/nx_set_tunnel.ex +++ b/lib/openflow/actions/nx_set_tunnel.ex @@ -5,17 +5,19 @@ defmodule Openflow.Action.NxSetTunnel do @nxast 2 alias __MODULE__ + alias Openflow.Action.Experimenter def new(tunnel_id) do %NxSetTunnel{tunnel_id: tunnel_id} end def to_binary(%NxSetTunnel{tunnel_id: tunnel_id}) do - exp_body = <<@experimenter::32, @nxast::16, 0::16, tunnel_id::32>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + 0::16, + tunnel_id::32 + >>) end def read(<<@experimenter::32, @nxast::16, _::16, tunnel_id::32>>) do diff --git a/lib/openflow/actions/nx_set_tunnel64.ex b/lib/openflow/actions/nx_set_tunnel64.ex index d729689..1bec4bd 100644 --- a/lib/openflow/actions/nx_set_tunnel64.ex +++ b/lib/openflow/actions/nx_set_tunnel64.ex @@ -5,17 +5,19 @@ defmodule Openflow.Action.NxSetTunnel64 do @nxast 9 alias __MODULE__ + alias Openflow.Action.Experimenter def new(tunnel_id) do %NxSetTunnel64{tunnel_id: tunnel_id} end def to_binary(%NxSetTunnel64{tunnel_id: tunnel_id}) do - exp_body = <<@experimenter::32, @nxast::16, 0::size(6)-unit(8), tunnel_id::64>> - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + 0::size(6)-unit(8), + tunnel_id::64 + >>) end def read(<<@experimenter::32, @nxast::16, 0::size(6)-unit(8), tunnel_id::64>>) do diff --git a/lib/openflow/actions/nx_stack_pop.ex b/lib/openflow/actions/nx_stack_pop.ex index 479932c..cc3be8c 100644 --- a/lib/openflow/actions/nx_stack_pop.ex +++ b/lib/openflow/actions/nx_stack_pop.ex @@ -9,26 +9,30 @@ defmodule Openflow.Action.NxStackPop do @nxast 28 alias __MODULE__ + alias Openflow.Action.Experimenter def new(options) do - field = Keyword.get(options, :field) + field = options[:field] || raise "field must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(field) - n_bits = Keyword.get(options, :n_bits, default_n_bits) - ofs = Keyword.get(options, :offset, 0) - %NxStackPop{n_bits: n_bits, offset: ofs, field: field} + + %NxStackPop{ + n_bits: options[:n_bits] || default_n_bits, + offset: options[:offset] || 0, + field: field + } end - def to_binary(%NxStackPop{n_bits: n_bits, offset: ofs, field: field}) do - field_bin = Openflow.Match.codec_header(field) + def to_binary(%NxStackPop{} = stack_pop) do + field_bin = Openflow.Match.codec_header(stack_pop.field) - exp_body = - <<@experimenter::32, @nxast::16, ofs::16, field_bin::4-bytes, n_bits::16, - 0::size(6)-unit(8)>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + stack_pop.offset::16, + field_bin::4-bytes, + stack_pop.n_bits::16, + 0::size(6)-unit(8) + >>) end def read( diff --git a/lib/openflow/actions/nx_stack_push.ex b/lib/openflow/actions/nx_stack_push.ex index aa33e71..b4eee19 100644 --- a/lib/openflow/actions/nx_stack_push.ex +++ b/lib/openflow/actions/nx_stack_push.ex @@ -9,26 +9,30 @@ defmodule Openflow.Action.NxStackPush do @nxast 27 alias __MODULE__ + alias Openflow.Action.Experimenter def new(options) do - field = Keyword.get(options, :field) + field = options[:field] || raise "field must be specified" default_n_bits = Openflow.Match.Field.n_bits_of(field) - n_bits = Keyword.get(options, :n_bits, default_n_bits) - ofs = Keyword.get(options, :offset, 0) - %NxStackPush{n_bits: n_bits, offset: ofs, field: field} + + %NxStackPush{ + n_bits: options[:n_bits] || default_n_bits, + offset: options[:offset] || 0, + field: field + } end - def to_binary(%NxStackPush{n_bits: n_bits, offset: ofs, field: field}) do - field_bin = Openflow.Match.codec_header(field) + def to_binary(%NxStackPush{} = stack_pop) do + field_bin = Openflow.Match.codec_header(stack_pop.field) - exp_body = - <<@experimenter::32, @nxast::16, ofs::16, field_bin::4-bytes, n_bits::16, - 0::size(6)-unit(8)>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + stack_pop.offset::16, + field_bin::4-bytes, + stack_pop.n_bits::16, + 0::size(6)-unit(8) + >>) end def read( diff --git a/lib/openflow/actions/nx_write_metadata.ex b/lib/openflow/actions/nx_write_metadata.ex index 4396d6a..50d05f5 100644 --- a/lib/openflow/actions/nx_write_metadata.ex +++ b/lib/openflow/actions/nx_write_metadata.ex @@ -8,25 +8,28 @@ defmodule Openflow.Action.NxWriteMetadata do @nxast 22 alias __MODULE__ + alias Openflow.Action.Experimenter + + def new(options \\ []) def new(metadata) when is_integer(metadata) do new(metadata: metadata) end def new(options) when is_list(options) do - metadata = Keyword.get(options, :metadata, 0) - metadata_mask = Keyword.get(options, :metadata_mask, 0xFFFFFFFFFFFFFFFF) + metadata = options[:metadata] || raise "metadata must be specified" + metadata_mask = options[:metadata_mask] || 0xFFFFFFFFFFFFFFFF %NxWriteMetadata{metadata: metadata, metadata_mask: metadata_mask} end def to_binary(%NxWriteMetadata{metadata: metadata, metadata_mask: metadata_mask}) do - exp_body = - <<@experimenter::32, @nxast::16, 0::size(6)-unit(8), metadata::64, metadata_mask::64>> - - exp_body_size = byte_size(exp_body) - padding_length = Openflow.Utils.padding(4 + exp_body_size, 8) - length = 4 + exp_body_size + padding_length - <<0xFFFF::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>> + Experimenter.pack_exp_header(<< + @experimenter::32, + @nxast::16, + 0::size(6)-unit(8), + metadata::64, + metadata_mask::64 + >>) end def read(<<@experimenter::32, @nxast::16, _::size(6)-unit(8), metadata::64, metadata_mask::64>>) do diff --git a/lib/openflow/actions/set_field.ex b/lib/openflow/actions/set_field.ex index 79b4070..8884e8f 100644 --- a/lib/openflow/actions/set_field.ex +++ b/lib/openflow/actions/set_field.ex @@ -7,13 +7,13 @@ defmodule Openflow.Action.SetField do def ofpat, do: 25 - def new({_field, _value} = oxm_field) do + def new([{_field, _value}] = oxm_field) do %SetField{field: oxm_field} end - def to_binary(%SetField{field: {field, value}}) do + def to_binary(%SetField{field: field}) do match_bin = - [{field, value}] + field |> Openflow.Match.new() |> Openflow.Match.to_binary() @@ -29,6 +29,6 @@ defmodule Openflow.Action.SetField do match_len = 4 + 4 + flen match_bin = <<1::16, match_len::16, match_field_bin::bytes>> {[field | _], _rest} = Openflow.Match.read(match_bin) - %SetField{field: field} + %SetField{field: [field]} end end diff --git a/lib/openflow/enum_gen.ex b/lib/openflow/enum_gen.ex index c4c7b57..2b259cc 100644 --- a/lib/openflow/enum_gen.ex +++ b/lib/openflow/enum_gen.ex @@ -800,8 +800,8 @@ defmodule Openflow.EnumGen do nicira_ext_action: [ {Openflow.Action.NxResubmit, 1}, {Openflow.Action.NxSetTunnel, 2}, - {Openflow.Action.NxSetQueue, 4}, - {Openflow.Action.NxPopQueue, 5}, + # {Openflow.Action.NxSetQueue, 4}, Deprecated + # {Openflow.Action.NxPopQueue, 5}, Deprecated {Openflow.Action.NxRegMove, 6}, {Openflow.Action.NxRegLoad, 7}, {Openflow.Action.NxNote, 8}, @@ -820,13 +820,13 @@ defmodule Openflow.EnumGen do {Openflow.Action.NxWriteMetadata, 22}, {Openflow.Action.NxPushMpls, 23}, {Openflow.Action.NxPopMpls, 24}, - {Openflow.Action.NxSetMplsTtl, 25}, - {Openflow.Action.NxDecMplsTtl, 26}, + # {Openflow.Action.NxSetMplsTtl, 25}, Deprecated + # {Openflow.Action.NxDecMplsTtl, 26}, Deprecated {Openflow.Action.NxStackPush, 27}, {Openflow.Action.NxStackPop, 28}, {Openflow.Action.NxSample, 29}, - {Openflow.Action.NxSetMplsLabel, 30}, - {Openflow.Action.NxSetMplsTc, 31}, + # {Openflow.Action.NxSetMplsLabel, 30}, Deprecated + # {Openflow.Action.NxSetMplsTc, 31}, Deprecated {Openflow.Action.NxOutputReg2, 32}, {Openflow.Action.NxRegLoad2, 33}, {Openflow.Action.NxConjunction, 34}, diff --git a/lib/openflow/onf_bundle_add.ex b/lib/openflow/onf_bundle_add.ex index 7b87c55..2f53b23 100644 --- a/lib/openflow/onf_bundle_add.ex +++ b/lib/openflow/onf_bundle_add.ex @@ -38,11 +38,14 @@ defmodule Openflow.OnfBundleAdd do pad_length = Openflow.Utils.pad_length(length, 8) flags_int = Openflow.Enums.flags_to_int(bundle_add.flags, :bundle_flags) - <<@experimenter::32, @onf_type::32, bundle_id::32, 0::2-unit(8), - flags_int::16, message_bin::bytes, 0::size(pad_length)-unit(8)>> + <<@experimenter::32, @onf_type::32, bundle_id::32, 0::2-unit(8), flags_int::16, + message_bin::bytes, 0::size(pad_length)-unit(8)>> end - def read(<<@experimenter::32, @onf_type::32, bundle_id::32, _pad::16, flags_int::16, message_bin::bytes>>) do + def read( + <<@experimenter::32, @onf_type::32, bundle_id::32, _pad::16, flags_int::16, + message_bin::bytes>> + ) do message = Openflow.read(message_bin) flags = Openflow.Enums.int_to_flags(flags_int, :bundle_flags) %OnfBundleAdd{bundle_id: bundle_id, flags: flags, message: message} diff --git a/lib/tres/message_helper.ex b/lib/tres/message_helper.ex index 136fe04..e3aa398 100644 --- a/lib/tres/message_helper.ex +++ b/lib/tres/message_helper.ex @@ -22,7 +22,13 @@ defmodule Tres.MessageHelper do send_message(flow_mod, datapath_id, Keyword.get(options, :blocking, false)) bundle_id when is_integer(bundle_id) -> - bundle = Openflow.OnfBundleAdd.new(bundle_id: bundle_id, flags: options[:bundle_flags] || [], message: flow_mod) + bundle = + Openflow.OnfBundleAdd.new( + bundle_id: bundle_id, + flags: options[:bundle_flags] || [], + message: flow_mod + ) + send_message(bundle, datapath_id, Keyword.get(options, :blocking, false)) end end @@ -48,7 +54,13 @@ defmodule Tres.MessageHelper do send_message(flow_mod, datapath_id, Keyword.get(options, :blocking, false)) bundle_id when is_integer(bundle_id) -> - bundle = Openflow.OnfBundleAdd.new(bundle_id: bundle_id, flags: options[:bundle_flags] || [], message: flow_mod) + bundle = + Openflow.OnfBundleAdd.new( + bundle_id: bundle_id, + flags: options[:bundle_flags] || [], + message: flow_mod + ) + send_message(bundle, datapath_id, Keyword.get(options, :blocking, false)) end end @@ -72,7 +84,13 @@ defmodule Tres.MessageHelper do send_message(flow_mod, datapath_id, Keyword.get(options, :blocking, false)) bundle_id when is_integer(bundle_id) -> - bundle = Openflow.OnfBundleAdd.new(bundle_id: bundle_id, flags: options[:bundle_flags] || [], message: flow_mod) + bundle = + Openflow.OnfBundleAdd.new( + bundle_id: bundle_id, + flags: options[:bundle_flags] || [], + message: flow_mod + ) + send_message(bundle, datapath_id, Keyword.get(options, :blocking, false)) end end @@ -127,7 +145,13 @@ defmodule Tres.MessageHelper do send_message(packet_out, datapath_id, Keyword.get(options, :blocking, false)) bundle_id when is_integer(bundle_id) -> - bundle = Openflow.OnfBundleAdd.new(bundle_id: bundle_id, flags: options[:bundle_flags], message: packet_out) + bundle = + Openflow.OnfBundleAdd.new( + bundle_id: bundle_id, + flags: options[:bundle_flags], + message: packet_out + ) + send_message(bundle, datapath_id, Keyword.get(options, :blocking, false)) end end @@ -147,7 +171,13 @@ defmodule Tres.MessageHelper do send_message(group_mod, datapath_id, Keyword.get(options, :blocking, false)) bundle_id when is_integer(bundle_id) -> - bundle = Openflow.OnfBundleAdd.new(bundle_id: bundle_id, flags: options[:bundle_flags] || [], message: group_mod) + bundle = + Openflow.OnfBundleAdd.new( + bundle_id: bundle_id, + flags: options[:bundle_flags] || [], + message: group_mod + ) + send_message(bundle, datapath_id, Keyword.get(options, :blocking, false)) end end @@ -165,7 +195,13 @@ defmodule Tres.MessageHelper do send_message(group_mod, datapath_id, Keyword.get(options, :blocking, false)) bundle_id when is_integer(bundle_id) -> - bundle = Openflow.OnfBundleAdd.new(bundle_id: bundle_id, flags: options[:bundle_flags] || [], message: group_mod) + bundle = + Openflow.OnfBundleAdd.new( + bundle_id: bundle_id, + flags: options[:bundle_flags] || [], + message: group_mod + ) + send_message(bundle, datapath_id, Keyword.get(options, :blocking, false)) end end @@ -185,7 +221,13 @@ defmodule Tres.MessageHelper do send_message(group_mod, datapath_id, Keyword.get(options, :blocking, false)) bundle_id when is_integer(bundle_id) -> - bundle = Openflow.OnfBundleAdd.new(bundle_id: bundle_id, flags: options[:bundle_flags] || [], message: group_mod) + bundle = + Openflow.OnfBundleAdd.new( + bundle_id: bundle_id, + flags: options[:bundle_flags] || [], + message: group_mod + ) + send_message(bundle, datapath_id, Keyword.get(options, :blocking, false)) end end @@ -246,25 +288,25 @@ defmodule Tres.MessageHelper do # ONF Bundle Control defp onf_bundle_open(datapath_id, options \\ []) do - options2 = Keyword.merge(options, [type: :open_request]) + options2 = Keyword.merge(options, type: :open_request) bundle = Openflow.OnfBundleControl.new(options2) send_message(bundle, datapath_id) end defp onf_bundle_close(datapath_id, options) do - options2 = Keyword.merge(options, [type: :close_request]) + options2 = Keyword.merge(options, type: :close_request) bundle = Openflow.OnfBundleControl.new(options2) send_message(bundle, datapath_id) end defp onf_bundle_commit(datapath_id, options) do - options2 = Keyword.merge(options, [type: :commit_request]) + options2 = Keyword.merge(options, type: :commit_request) bundle = Openflow.OnfBundleControl.new(options2) send_message(bundle, datapath_id) end defp onf_bundle_discard(datapath_id, options) do - options2 = Keyword.merge(options, [type: :discard_request]) + options2 = Keyword.merge(options, type: :discard_request) bundle = Openflow.OnfBundleControl.new(options2) send_message(bundle, datapath_id) end diff --git a/test/ofp_action_test.exs b/test/ofp_action_test.exs index 5580700..0304e14 100644 --- a/test/ofp_action_test.exs +++ b/test/ofp_action_test.exs @@ -2,37 +2,47 @@ defmodule OfpActionTest do use ExUnit.Case doctest Openflow - test "Openflow.Action.NxBundle" do - test_file = "test/packet_data/nx_bundle.raw" - packet = File.read!(test_file) - actions = Openflow.Action.read(packet) + describe "Openflow.Action.NxBundle" do + test "with a binary" do + test_file = "test/packet_data/nx_bundle.raw" + packet = File.read!(test_file) + actions = Openflow.Action.read(packet) - bundle = - Openflow.Action.NxBundle.new( - algorithm: :highest_random_weight, - slaves: [4, 8] - ) + bundle = + Openflow.Action.NxBundle.new( + algorithm: :highest_random_weight, + slaves: [4, 8] + ) - actions_bin = Openflow.Action.to_binary(bundle) - assert actions_bin == packet - assert actions == [bundle] + actions_bin = Openflow.Action.to_binary(bundle) + assert actions_bin == packet + assert actions == [bundle] + end end - test "Openflow.Action.NxBundleLoad" do - test_file = "test/packet_data/nx_bundle_load.raw" - packet = File.read!(test_file) - actions = Openflow.Action.read(packet) + describe "Openflow.Action.NxBundleLoad" do + test "with a binary" do + test_file = "test/packet_data/nx_bundle_load.raw" + packet = File.read!(test_file) + actions = Openflow.Action.read(packet) - bundle_load = - Openflow.Action.NxBundleLoad.new( - algorithm: :highest_random_weight, - slaves: [4, 8], - dst_field: :reg0 - ) + bundle_load = + Openflow.Action.NxBundleLoad.new( + algorithm: :highest_random_weight, + slaves: [4, 8], + dst_field: :reg0 + ) - actions_bin = Openflow.Action.to_binary(bundle_load) - assert actions_bin == packet - assert actions == [bundle_load] + actions_bin = Openflow.Action.to_binary(bundle_load) + assert actions_bin == packet + assert actions == [bundle_load] + end + + test "with no option" do + assert_raise RuntimeError, "dst_field must be specified", fn -> + Openflow.Action.NxBundleLoad.new([]) + end + end end test "Openflow.Action.NxController" do @@ -52,20 +62,30 @@ defmodule OfpActionTest do assert actions == [controller] end - test "Openflow.Action.NxController2" do - test_file = "test/packet_data/nx_controller2.raw" - packet = File.read!(test_file) - actions = Openflow.Action.read(packet) + describe "Openflow.Action.NxController2" do + test "with packet data" do + test_file = "test/packet_data/nx_controller2.raw" + packet = File.read!(test_file) + actions = Openflow.Action.read(packet) - controller2 = - Openflow.Action.NxController2.new( - max_len: 1234, - reason: :invalid_ttl, - userdata: <<1, 2, 3, 4, 5>>, - pause: true - ) + controller2 = + Openflow.Action.NxController2.new( + max_len: 1234, + id: 5678, + reason: :invalid_ttl, + userdata: <<1, 2, 3, 4, 5>>, + pause: true + ) - assert actions == [controller2] + assert actions == [controller2] + + controller2 + |> Openflow.Action.NxController2.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(controller2) + |> assert() + end end describe "Openflow.Action.NxConntrack" do @@ -412,7 +432,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [ct] end + end + describe "Openflow.Action.NxCtClear" do test "with ct_clear" do test_file = "test/packet_data/nx_ct_clear.raw" packet = File.read!(test_file) @@ -422,7 +444,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [ct] end + end + describe "Openflow.Action.NxDecTtl" do test "with dec_ttl" do test_file = "test/packet_data/nx_dec_ttl.raw" packet = File.read!(test_file) @@ -432,7 +456,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [dec_ttl] end + end + describe "Openflow.Action.NxDecTtlCntIds" do test "with dec_ttl_cnt_ids" do test_file = "test/packet_data/nx_dec_ttl_cnt_ids.raw" packet = File.read!(test_file) @@ -442,7 +468,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [dec_ttl] end + end + describe "Openflow.Action.NxExit" do test "with exit" do test_file = "test/packet_data/nx_exit.raw" packet = File.read!(test_file) @@ -452,7 +480,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [exit] end + end + describe "Openflow.Action.NxFinTimeout" do test "with fin_timeout" do test_file = "test/packet_data/nx_fin_timeout.raw" packet = File.read!(test_file) @@ -462,7 +492,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [fin_timeout] end + end + describe "Openflow.Action.NxLearn" do test "with learn" do test_file = "test/packet_data/nx_learn.raw" packet = File.read!(test_file) @@ -489,7 +521,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [learn] end + end + describe "Openflow.Action.NxLearn2" do test "with learn2" do test_file = "test/packet_data/nx_learn2.raw" packet = File.read!(test_file) @@ -519,7 +553,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [learn2] end + end + describe "Openflow.Action.NxMultipath" do test "with multipath" do test_file = "test/packet_data/nx_multipath.raw" packet = File.read!(test_file) @@ -536,8 +572,10 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [multipath] end + end - test "with note" do + describe "Openflow.Action.NxNote" do + test "with note binary" do test_file = "test/packet_data/nx_note.raw" packet = File.read!(test_file) actions = Openflow.Action.read(packet) @@ -546,8 +584,10 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [note] end + end - test "with output_reg" do + describe "Openflow.Action.NxOutputReg" do + test "with output_reg options src_field = reg1, n_bits = 6, offset = 5" do test_file = "test/packet_data/nx_output_reg.raw" packet = File.read!(test_file) actions = Openflow.Action.read(packet) @@ -556,28 +596,35 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [output_reg] end + end - test "with output_trunc" do + describe "Openflow.Action.NxOutputReg2" do + test "with output_reg options src_field = reg1, n_bits = 6, offset = 5" do + output_reg = Openflow.Action.NxOutputReg2.new(src_field: :reg1, n_bits: 6, offset: 5) + + output_reg + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(output_reg) + |> assert() + end + end + + describe "Openflow.Action.NxOutputTrunc" do + test "with output_trunc options: packets output to port1 trunc in 100bytes" do test_file = "test/packet_data/nx_output_trunc.raw" packet = File.read!(test_file) actions = Openflow.Action.read(packet) - output_trunc = Openflow.Action.NxOutputTrunc.new(port_number: 1, max_len: 100) + output_trunc = Openflow.Action.NxOutputTrunc.new(port_no: 1, max_len: 100) actions_bin = Openflow.Action.to_binary(output_trunc) assert actions_bin == packet assert actions == [output_trunc] end + end - test "with pop_queue" do - test_file = "test/packet_data/nx_pop_queue.raw" - packet = File.read!(test_file) - actions = Openflow.Action.read(packet) - pop_queue = Openflow.Action.NxPopQueue.new() - actions_bin = Openflow.Action.to_binary(pop_queue) - assert actions_bin == packet - assert actions == [pop_queue] - end - - test "with reg_load" do + describe "Openflow.Action.NxRegLoad" do + test "with options: load 0xf008 to vlan_tci" do test_file = "test/packet_data/nx_reg_load.raw" packet = File.read!(test_file) actions = Openflow.Action.read(packet) @@ -586,8 +633,10 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [reg_load] end + end - test "with reg_move" do + describe "Openflow.Action.NxRegMove" do + test "with options: move in_port value to vlan_tci field" do test_file = "test/packet_data/nx_reg_move.raw" packet = File.read!(test_file) actions = Openflow.Action.read(packet) @@ -596,17 +645,21 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [reg_move] end + end - test "with resubmit" do + describe "Openflow.Action.NxResubmit" do + test "with options: resubmit to table, search with the port_no" do test_file = "test/packet_data/nx_resubmit.raw" packet = File.read!(test_file) actions = Openflow.Action.read(packet) - resubmit = Openflow.Action.NxResubmit.new(5) + resubmit = Openflow.Action.NxResubmit.new(_port_no = 5) actions_bin = Openflow.Action.to_binary(resubmit) assert actions_bin == packet assert actions == [resubmit] end + end + describe "Openflow.Action.NxResubmitTable" do test "with resubmit_table" do test_file = "test/packet_data/nx_resubmit_table.raw" packet = File.read!(test_file) @@ -616,7 +669,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [resubmit_table] end + end + describe "Openflow.Action.NxResubmitTableCt" do test "with resubmit_table_ct" do test_file = "test/packet_data/nx_resubmit_table_ct.raw" packet = File.read!(test_file) @@ -626,7 +681,9 @@ defmodule OfpActionTest do assert actions_bin == packet assert actions == [resubmit_table_ct] end + end + describe "Openflow.Action.NxClone" do test "with clone(push_vlan:0x8100,set_field:5->vlan_vid,output:10)" do test_file = "test/packet_data/nx_clone.raw" packet = File.read!(test_file) @@ -635,7 +692,7 @@ defmodule OfpActionTest do clone = Openflow.Action.NxClone.new([ Openflow.Action.PushVlan.new(), - Openflow.Action.SetField.new({:vlan_vid, 5}), + Openflow.Action.SetField.new(vlan_vid: 5), Openflow.Action.Output.new(10) ]) @@ -644,4 +701,143 @@ defmodule OfpActionTest do assert actions == [clone] end end + + describe "Openflow.Action.NxRegLoad2" do + test "with set_field:0x1/0x1->reg1" do + reg_load2 = Openflow.Action.NxRegLoad2.new(reg1: {1, 1}) + + reg_load2 + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(reg_load2) + |> assert() + end + + test "with set_field:0x1->reg1" do + reg_load2 = Openflow.Action.NxRegLoad2.new(reg1: 1) + + reg_load2 + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(reg_load2) + |> assert() + end + end + + describe "Openflow.Action.NxStackPop" do + test "with pop:NXM_NX_REG0[]" do + pop = Openflow.Action.NxStackPop.new(field: :reg0) + + assert pop.n_bits == 32 + assert pop.offset == 0 + + pop + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(pop) + |> assert() + end + + test "with pop:NXM_NX_REG0[1..31]" do + pop = Openflow.Action.NxStackPop.new(field: :reg0, offset: 1, n_bits: 31) + + assert pop.n_bits == 31 + assert pop.offset == 1 + + pop + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(pop) + |> assert() + end + end + + describe "Openflow.Action.NxSetTunnel" do + test "with set_tunnel:0x1" do + set_tunnel = Openflow.Action.NxSetTunnel.new(1) + + set_tunnel + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(set_tunnel) + |> assert() + end + end + + describe "Openflow.Action.NxSetTunnel64" do + test "with set_tunnel64:0x1" do + set_tunnel = Openflow.Action.NxSetTunnel64.new(1) + + set_tunnel + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(set_tunnel) + |> assert() + end + end + + describe "Openflow.Action.NxWriteMetadata" do + test "with write_metadata:0x1" do + write_metadata = Openflow.Action.NxWriteMetadata.new(1) + + write_metadata + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(write_metadata) + |> assert() + end + + test "with write_metadata:0x1/0x1" do + write_metadata = Openflow.Action.NxWriteMetadata.new(metadata: 0x1, metadata_mask: 0x1) + + write_metadata + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(write_metadata) + |> assert() + end + + test "with no options" do + assert_raise RuntimeError, "metadata must be specified", fn -> + Openflow.Action.NxWriteMetadata.new() + end + end + end + + describe "Openflow.Action.NxConjunction" do + test "with conjunction(0,1/2)" do + conjunction = Openflow.Action.NxConjunction.new(clause: 0, n_clauses: 2) + + assert conjunction.id == 0 + assert conjunction.clause == 1 + assert conjunction.n_clauses == 2 + + conjunction + |> Openflow.Action.to_binary() + |> Openflow.Action.read() + |> Enum.at(0) + |> Kernel.==(conjunction) + |> assert() + end + end + + test "with no n_clauses option" do + assert_raise RuntimeError, "n_clauses must be specified", fn -> + Openflow.Action.NxConjunction.new(id: 1, clause: 0) + end + end + + test "with n_clauses option less than 2" do + assert_raise RuntimeError, "n_clauses must be greater than 1", fn -> + Openflow.Action.NxConjunction.new(id: 1, clause: 0, n_clauses: 1) + end + end end diff --git a/test/ofp_flow_mod_test.exs b/test/ofp_flow_mod_test.exs index 9671698..762eb12 100644 --- a/test/ofp_flow_mod_test.exs +++ b/test/ofp_flow_mod_test.exs @@ -31,7 +31,7 @@ defmodule OfpFlowModTest do assert fm.instructions == [ Openflow.Instruction.WriteActions.new([ - Openflow.Action.SetField.new({:vlan_vid, 258}), + Openflow.Action.SetField.new(vlan_vid: 258), Openflow.Action.CopyTtlOut.new(), Openflow.Action.CopyTtlIn.new(), Openflow.Action.CopyTtlIn.new(), @@ -51,8 +51,8 @@ defmodule OfpFlowModTest do Openflow.Action.Output.new(6) ]), Openflow.Instruction.ApplyActions.new([ - Openflow.Action.SetField.new({:eth_src, "010203040506"}), - Openflow.Action.SetField.new({:onf_pbb_uca, 1}) + Openflow.Action.SetField.new(eth_src: "010203040506"), + Openflow.Action.SetField.new(onf_pbb_uca: 1) ]) ] @@ -202,7 +202,7 @@ defmodule OfpFlowModTest do assert fm.instructions == [ Openflow.Instruction.ApplyActions.new([ Openflow.Action.PopVlan.new(), - Openflow.Action.SetField.new({:ipv4_dst, {192, 168, 2, 9}}), + Openflow.Action.SetField.new(ipv4_dst: {192, 168, 2, 9}), Openflow.Action.NxLearn.new( hard_timeout: 300, priority: 1, @@ -263,7 +263,7 @@ defmodule OfpFlowModTest do assert fm.instructions == [ Openflow.Instruction.ApplyActions.new([ - Openflow.Action.NxConjunction.new(clause: 1, id: 0xABCDEF, n_clauses: 2) + Openflow.Action.NxConjunction.new(clause: 0, id: 0xABCDEF, n_clauses: 2) ]) ] @@ -290,7 +290,7 @@ defmodule OfpFlowModTest do assert fm.instructions == [ Openflow.Instruction.ApplyActions.new([ Openflow.Action.PopVlan.new(), - Openflow.Action.SetField.new({:ipv4_dst, {192, 168, 2, 9}}) + Openflow.Action.SetField.new(ipv4_dst: {192, 168, 2, 9}) ]), Openflow.Instruction.GotoTable.new(100) ] diff --git a/test/packet_data/nx_reg_load2.raw b/test/packet_data/nx_reg_load2.raw new file mode 100644 index 0000000..08a2b89 Binary files /dev/null and b/test/packet_data/nx_reg_load2.raw differ