diff --git a/lib/openflow/actions/nx_conjunction.ex b/lib/openflow/actions/nx_conjunction.ex index 0760ecb..5aa65cf 100644 --- a/lib/openflow/actions/nx_conjunction.ex +++ b/lib/openflow/actions/nx_conjunction.ex @@ -11,7 +11,8 @@ defmodule Openflow.Action.NxConjunction do alias __MODULE__ alias Openflow.Action.Experimenter - def new(options \\ []) do + @spec new(Keyword.t()) :: %NxConjunction{} + 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" diff --git a/lib/openflow/actions/nx_controller.ex b/lib/openflow/actions/nx_controller.ex index 0086d22..a125abe 100644 --- a/lib/openflow/actions/nx_controller.ex +++ b/lib/openflow/actions/nx_controller.ex @@ -11,6 +11,20 @@ defmodule Openflow.Action.NxController do alias __MODULE__ alias Openflow.Action.Experimenter + @type max_len :: :max | :no_buffer | non_neg_integer() + @type packet_in_reason :: + :no_match | :action | :invalid_ttl | :action_set | :group | :packet_out + @type t :: %NxController{ + max_len: max_len(), + id: non_neg_integer(), + reason: packet_in_reason() + } + + @spec new( + max_len: max_len(), + id: non_neg_integer(), + reason: packet_in_reason() + ) :: t() def new(options \\ []) do %NxController{ max_len: options[:max_len] || :no_buffer, diff --git a/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex b/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex index 6cf6107..d3303fa 100644 --- a/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex +++ b/lib/openflow/actions/nx_dec_ttl_cnt_ids.ex @@ -7,7 +7,10 @@ defmodule Openflow.Action.NxDecTtlCntIds do alias __MODULE__ alias Openflow.Action.Experimenter - def new(ids \\ []) do + @type t :: %NxDecTtlCntIds{ids: [non_neg_integer()]} + + @spec new(ids :: [non_neg_integer()]) :: t() + def new(ids) do %NxDecTtlCntIds{ids: ids} end diff --git a/lib/openflow/actions/nx_fin_timeout.ex b/lib/openflow/actions/nx_fin_timeout.ex index bd3e7ad..e9db357 100644 --- a/lib/openflow/actions/nx_fin_timeout.ex +++ b/lib/openflow/actions/nx_fin_timeout.ex @@ -10,7 +10,8 @@ defmodule Openflow.Action.NxFinTimeout do alias __MODULE__ alias Openflow.Action.Experimenter - def new(options \\ []) do + @spec new(Keyword.t()) :: %NxFinTimeout{} + def new(options) do %NxFinTimeout{ idle_timeout: options[:idle_timeout] || 0, hard_timeout: options[:hard_timeout] || 0 diff --git a/lib/openflow/actions/nx_multipath.ex b/lib/openflow/actions/nx_multipath.ex index b058250..1e7c693 100644 --- a/lib/openflow/actions/nx_multipath.ex +++ b/lib/openflow/actions/nx_multipath.ex @@ -18,7 +18,8 @@ defmodule Openflow.Action.NxMultipath do alias __MODULE__ alias Openflow.Action.Experimenter - def new(options \\ []) do + @spec new(Keyword.t()) :: %NxMultipath{} + 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) diff --git a/lib/openflow/actions/nx_output_reg.ex b/lib/openflow/actions/nx_output_reg.ex index d0d484b..a5efe89 100644 --- a/lib/openflow/actions/nx_output_reg.ex +++ b/lib/openflow/actions/nx_output_reg.ex @@ -14,7 +14,21 @@ defmodule Openflow.Action.NxOutputReg do alias __MODULE__ alias Openflow.Action.Experimenter - def new(options \\ []) do + @type max_len :: :no_buffer | :max | non_neg_integer() + @type t :: %NxOutputReg{ + n_bits: pos_integer(), + offset: non_neg_integer(), + src_field: atom(), + max_len: max_len() + } + + @spec new( + n_bits: pos_integer(), + offset: non_neg_integer(), + src_field: atom(), + max_len: max_len() + ) :: t() + 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) diff --git a/lib/openflow/actions/nx_output_reg2.ex b/lib/openflow/actions/nx_output_reg2.ex index d430190..bfaf212 100644 --- a/lib/openflow/actions/nx_output_reg2.ex +++ b/lib/openflow/actions/nx_output_reg2.ex @@ -14,7 +14,21 @@ defmodule Openflow.Action.NxOutputReg2 do alias __MODULE__ alias Openflow.Action.Experimenter - def new(options \\ []) do + @type max_len :: :no_buffer | :max | non_neg_integer() + @type t :: %NxOutputReg2{ + n_bits: pos_integer(), + offset: non_neg_integer(), + src_field: atom(), + max_len: max_len() + } + + @spec new( + n_bits: pos_integer(), + offset: non_neg_integer(), + src_field: atom(), + max_len: max_len() + ) :: t() + 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) diff --git a/lib/openflow/actions/nx_output_trunc.ex b/lib/openflow/actions/nx_output_trunc.ex index d5b1c56..e60acb7 100644 --- a/lib/openflow/actions/nx_output_trunc.ex +++ b/lib/openflow/actions/nx_output_trunc.ex @@ -10,7 +10,8 @@ defmodule Openflow.Action.NxOutputTrunc do alias __MODULE__ alias Openflow.Action.Experimenter - def new(options \\ []) do + @spec new(Keyword.t()) :: %NxOutputTrunc{} + 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" diff --git a/test/ofp_action_test.exs b/test/ofp_action_test.exs index 1387363..2288e8a 100644 --- a/test/ofp_action_test.exs +++ b/test/ofp_action_test.exs @@ -32,6 +32,14 @@ defmodule OfpActionTest do end end + describe "Openflow.Action.Experimenter" do + test "with exp_id and data" do + experimenter = Openflow.Action.Experimenter.new(0xDEADBEEF) + assert experimenter.exp_id == 0xDEADBEEF + assert experimenter.data == "" + end + end + describe "Openflow.Action.DecMplsTtl" do test "with no options" do dec_mpls_ttl = Openflow.Action.DecMplsTtl.new() @@ -226,21 +234,30 @@ defmodule OfpActionTest do end end - test "Openflow.Action.NxController" do - test_file = "test/packet_data/nx_controller.raw" - packet = File.read!(test_file) - actions = Openflow.Action.read(packet) + describe "Openflow.Action.NxController" do + test "with packet_data" do + test_file = "test/packet_data/nx_controller.raw" + packet = File.read!(test_file) + actions = Openflow.Action.read(packet) - controller = - Openflow.Action.NxController.new( - max_len: 1234, - reason: :invalid_ttl, - id: 5678 - ) + controller = + Openflow.Action.NxController.new( + max_len: 1234, + reason: :invalid_ttl, + id: 5678 + ) - actions_bin = Openflow.Action.to_binary(controller) - assert actions_bin == packet - assert actions == [controller] + actions_bin = Openflow.Action.to_binary(controller) + assert actions_bin == packet + assert actions == [controller] + end + + test "with no options" do + controller = Openflow.Action.NxController.new() + assert controller.max_len == :no_buffer + assert controller.id == 0 + assert controller.reason == :action + end end describe "Openflow.Action.NxController2" do @@ -898,8 +915,12 @@ defmodule OfpActionTest do multipath = Openflow.Action.NxMultipath.new( + hash_field: :eth_src, algorithm: :modulo_n, basis: 50, + max_link: 0, + offset: 0, + argument: 0, dst_field: :reg0 ) @@ -926,16 +947,36 @@ defmodule OfpActionTest do test_file = "test/packet_data/nx_output_reg.raw" packet = File.read!(test_file) actions = Openflow.Action.read(packet) - output_reg = Openflow.Action.NxOutputReg.new(src_field: :reg1, n_bits: 6, offset: 5) + + output_reg = + Openflow.Action.NxOutputReg.new( + src_field: :reg1, + n_bits: 6, + offset: 5, + max_len: :no_buffer + ) + actions_bin = Openflow.Action.to_binary(output_reg) assert actions_bin == packet assert actions == [output_reg] end + + test "with no src_field option" do + assert_raise RuntimeError, "src_field must be specified", fn -> + Openflow.Action.NxOutputReg.new(n_bits: 6) + end + end end 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.NxOutputReg2.new( + src_field: :reg1, + n_bits: 6, + offset: 5, + max_len: :no_buffer + ) output_reg |> Openflow.Action.to_binary()