quality: Add test cases for instructions
This commit is contained in:
parent
b4c6f0822c
commit
a0ee397921
9 changed files with 120 additions and 43 deletions
|
|
@ -1,18 +1,31 @@
|
||||||
defmodule Openflow.Instruction do
|
defmodule Openflow.Instruction do
|
||||||
def read(instruction_bin) do
|
@moduledoc """
|
||||||
do_read([], instruction_bin)
|
Openflow instruction codec handler
|
||||||
end
|
"""
|
||||||
|
|
||||||
def to_binary(instructions) when is_list(instructions) do
|
@type instruction ::
|
||||||
to_binary(<<>>, instructions)
|
Openflow.Instruction.ApplyActions.t()
|
||||||
end
|
| Openflow.Instruction.WriteActions.t()
|
||||||
|
| Openflow.Instruction.ClearActions.t()
|
||||||
|
| Openflow.Instruction.GotoTable.t()
|
||||||
|
| Openflow.Instruction.WriteMetadata.t()
|
||||||
|
| Openflow.Instruction.Meter.t()
|
||||||
|
|
||||||
def to_binary(instruction) do
|
@spec read(<<_::32, _::_*8>>) :: [instruction()]
|
||||||
to_binary([instruction])
|
def read(instruction_bin),
|
||||||
end
|
do: do_read([], instruction_bin)
|
||||||
|
|
||||||
|
@spec to_binary(instruction()) :: <<_::32, _::_*8>>
|
||||||
|
def to_binary(instructions) when is_list(instructions),
|
||||||
|
do: to_binary(<<>>, instructions)
|
||||||
|
|
||||||
|
@spec to_binary([instruction()]) :: <<_::32, _::_*8>>
|
||||||
|
def to_binary(instruction),
|
||||||
|
do: to_binary([instruction])
|
||||||
|
|
||||||
# private functions
|
# private functions
|
||||||
|
|
||||||
|
@spec do_read([instruction()], <<_::_*8>>) :: [instruction()]
|
||||||
defp do_read(acc, <<>>), do: Enum.reverse(acc)
|
defp do_read(acc, <<>>), do: Enum.reverse(acc)
|
||||||
|
|
||||||
defp do_read(acc, <<type::16, length::16, _::bytes>> = binary) do
|
defp do_read(acc, <<type::16, length::16, _::bytes>> = binary) do
|
||||||
|
|
@ -21,6 +34,7 @@ defmodule Openflow.Instruction do
|
||||||
do_read([codec.read(instruction_bin) | acc], rest)
|
do_read([codec.read(instruction_bin) | acc], rest)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec to_binary(<<_::_*8>>) :: [instruction()]
|
||||||
defp to_binary(acc, []), do: acc
|
defp to_binary(acc, []), do: acc
|
||||||
|
|
||||||
defp to_binary(acc, [instruction | rest]) do
|
defp to_binary(acc, [instruction | rest]) do
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,19 @@ defmodule Openflow.Instruction.ApplyActions do
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
||||||
def new(actions) do
|
@type t :: %ApplyActions{actions: [Openflow.Action.type()]}
|
||||||
%ApplyActions{actions: actions}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
@spec new(Openflow.Action.type() | [Openflow.Action.type()]) :: t()
|
||||||
|
def new(actions), do: %ApplyActions{actions: actions}
|
||||||
|
|
||||||
|
@spec to_binary(t()) :: <<_::64, _::_*8>>
|
||||||
def to_binary(%ApplyActions{actions: actions}) do
|
def to_binary(%ApplyActions{actions: actions}) do
|
||||||
actions_bin = Openflow.Action.to_binary(actions)
|
actions_bin = Openflow.Action.to_binary(actions)
|
||||||
length = 8 + byte_size(actions_bin)
|
length = 8 + byte_size(actions_bin)
|
||||||
<<4::16, length::16, 0::size(4)-unit(8), actions_bin::bytes>>
|
<<4::16, length::16, 0::size(4)-unit(8), actions_bin::bytes>>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec read(<<_::64, _::_*8>>) :: t()
|
||||||
def read(<<4::16, _length::16, _::size(4)-unit(8), actions_bin::bytes>>) do
|
def read(<<4::16, _length::16, _::size(4)-unit(8), actions_bin::bytes>>) do
|
||||||
actions = Openflow.Action.read(actions_bin)
|
actions = Openflow.Action.read(actions_bin)
|
||||||
%ApplyActions{actions: actions}
|
%ApplyActions{actions: actions}
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,17 @@ defmodule Openflow.Instruction.ClearActions do
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
||||||
def new do
|
@type t :: %ClearActions{}
|
||||||
%ClearActions{}
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_binary(%ClearActions{}) do
|
@spec new() :: t()
|
||||||
actions_bin = ""
|
def new,
|
||||||
length = 8 + byte_size(actions_bin)
|
do: %ClearActions{}
|
||||||
<<5::16, length::16, 0::size(4)-unit(8), actions_bin::bytes>>
|
|
||||||
end
|
|
||||||
|
|
||||||
def read(<<5::16, _length::16, _::size(4)-unit(8), _::bytes>>) do
|
@spec to_binary(t()) :: <<_::64>>
|
||||||
%ClearActions{}
|
def to_binary(%ClearActions{}),
|
||||||
end
|
do: <<5::16, 8::16, 0::32>>
|
||||||
|
|
||||||
|
@spec read(<<_::64, _::_*8>>) :: t()
|
||||||
|
def read(<<5::16, _length::16, _::size(4)-unit(8), _::bytes>>),
|
||||||
|
do: %ClearActions{}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,19 @@ defmodule Openflow.Instruction.Experimenter do
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
||||||
def new(exp_id, data \\ "") do
|
@type t :: %Experimenter{exp_id: 0..0xFFFFFFFF, data: binary()}
|
||||||
%Experimenter{exp_id: exp_id, data: data}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
@spec new(exp_id :: 0..0xFFFFFFFF, data :: String.t()) :: t()
|
||||||
|
def new(exp_id, data \\ ""),
|
||||||
|
do: %Experimenter{exp_id: exp_id, data: data}
|
||||||
|
|
||||||
|
@spec to_binary(t()) :: <<_::64, _::_*8>>
|
||||||
def to_binary(%Experimenter{exp_id: exp_id, data: data}) do
|
def to_binary(%Experimenter{exp_id: exp_id, data: data}) do
|
||||||
length = 8 + byte_size(data)
|
length = 8 + byte_size(data)
|
||||||
<<0xFFFF::16, length::16, exp_id::32, data::bytes>>
|
<<0xFFFF::16, length::16, exp_id::32, data::bytes>>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec read(<<_::64, _::_*8>>) :: t()
|
||||||
def read(<<0xFFFF::16, _::16, exp_id::32, data::bytes>>) do
|
def read(<<0xFFFF::16, _::16, exp_id::32, data::bytes>>) do
|
||||||
%Experimenter{exp_id: exp_id, data: data}
|
%Experimenter{exp_id: exp_id, data: data}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,18 @@ defmodule Openflow.Instruction.GotoTable do
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
||||||
def new(table_id) do
|
@type t :: %GotoTable{table_id: 0..0xFF}
|
||||||
%GotoTable{table_id: table_id}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
@spec new(table_id :: 0..0xFF) :: t()
|
||||||
|
def new(table_id), do: %GotoTable{table_id: table_id}
|
||||||
|
|
||||||
|
@spec to_binary(t()) :: <<_::64>>
|
||||||
def to_binary(%GotoTable{table_id: table_id}) do
|
def to_binary(%GotoTable{table_id: table_id}) do
|
||||||
table_id_int = Openflow.Utils.get_enum(table_id, :table_id)
|
table_id_int = Openflow.Utils.get_enum(table_id, :table_id)
|
||||||
<<1::16, 8::16, table_id_int::8, 0::size(3)-unit(8)>>
|
<<1::16, 8::16, table_id_int::8, 0::size(3)-unit(8)>>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec read(<<_::64>>) :: t()
|
||||||
def read(<<1::16, 8::16, table_id_int::8, _::size(3)-unit(8)>>) do
|
def read(<<1::16, 8::16, table_id_int::8, _::size(3)-unit(8)>>) do
|
||||||
table_id = Openflow.Utils.get_enum(table_id_int, :table_id)
|
table_id = Openflow.Utils.get_enum(table_id_int, :table_id)
|
||||||
%GotoTable{table_id: table_id}
|
%GotoTable{table_id: table_id}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,18 @@ defmodule Openflow.Instruction.Meter do
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
||||||
def new(meter_id) do
|
@type t :: %Meter{meter_id: 0..0xFFFFFFFF}
|
||||||
%Meter{meter_id: meter_id}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
@spec new(meter_id :: 0..0xFFFFFFFF) :: t()
|
||||||
|
def new(meter_id), do: %Meter{meter_id: meter_id}
|
||||||
|
|
||||||
|
@spec to_binary(t()) :: <<_::64>>
|
||||||
def to_binary(%Meter{meter_id: meter_id}) do
|
def to_binary(%Meter{meter_id: meter_id}) do
|
||||||
meter_id_int = Openflow.Utils.get_enum(meter_id, :meter_id)
|
meter_id_int = Openflow.Utils.get_enum(meter_id, :meter_id)
|
||||||
<<6::16, 8::16, meter_id_int::32>>
|
<<6::16, 8::16, meter_id_int::32>>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec read(<<_::64>>) :: t()
|
||||||
def read(<<6::16, _::16, meter_id_int::32>>) do
|
def read(<<6::16, _::16, meter_id_int::32>>) do
|
||||||
meter_id = Openflow.Utils.get_enum(meter_id_int, :meter_id)
|
meter_id = Openflow.Utils.get_enum(meter_id_int, :meter_id)
|
||||||
%Meter{meter_id: meter_id}
|
%Meter{meter_id: meter_id}
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,19 @@ defmodule Openflow.Instruction.WriteActions do
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
||||||
def new(actions) do
|
@type t :: %WriteActions{actions: [Openflow.Action.type()]}
|
||||||
%WriteActions{actions: actions}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
@spec new(Openflow.Action.type() | [Openflow.Action.type()]) :: t()
|
||||||
|
def new(actions), do: %WriteActions{actions: actions}
|
||||||
|
|
||||||
|
@spec to_binary(t()) :: <<_::32, _::_*8>>
|
||||||
def to_binary(%WriteActions{actions: actions}) do
|
def to_binary(%WriteActions{actions: actions}) do
|
||||||
actions_bin = Openflow.Action.to_binary(actions)
|
actions_bin = Openflow.Action.to_binary(actions)
|
||||||
length = 8 + byte_size(actions_bin)
|
length = 8 + byte_size(actions_bin)
|
||||||
<<3::16, length::16, 0::size(4)-unit(8), actions_bin::bytes>>
|
<<3::16, length::16, 0::size(4)-unit(8), actions_bin::bytes>>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec read(<<_::32, _::_*8>>) :: t()
|
||||||
def read(<<3::16, _length::16, _::size(4)-unit(8), actions_bin::bytes>>) do
|
def read(<<3::16, _length::16, _::size(4)-unit(8), actions_bin::bytes>>) do
|
||||||
actions = Openflow.Action.read(actions_bin)
|
actions = Openflow.Action.read(actions_bin)
|
||||||
%WriteActions{actions: actions}
|
%WriteActions{actions: actions}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,31 @@
|
||||||
defmodule Openflow.Instruction.WriteMetadata do
|
defmodule Openflow.Instruction.WriteMetadata do
|
||||||
defstruct(metadata: 0, metadata_mask: 0xFFFFFFFFFFFFFFFF)
|
defstruct(value: 0, mask: 0xFFFFFFFFFFFFFFFF)
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
||||||
|
@type t :: %WriteMetadata{
|
||||||
|
value: 0..0xFFFFFFFFFFFFFFFF,
|
||||||
|
mask: 0..0xFFFFFFFFFFFFFFFF
|
||||||
|
}
|
||||||
|
|
||||||
|
@spec new(
|
||||||
|
value: 0..0xFFFFFFFFFFFFFFFF,
|
||||||
|
mask: 0..0xFFFFFFFFFFFFFFFF
|
||||||
|
) :: t()
|
||||||
def new(options) do
|
def new(options) do
|
||||||
metadata = Keyword.get(options, :metadata, 0)
|
%WriteMetadata{
|
||||||
metadata_mask = Keyword.get(options, :metadata_mask, 0xFFFFFFFFFFFFFFFF)
|
value: options[:value] || 0,
|
||||||
%WriteMetadata{metadata: metadata, metadata_mask: metadata_mask}
|
mask: options[:mask] || 0xFFFFFFFFFFFFFFFF
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_binary(%WriteMetadata{metadata: metadata, metadata_mask: metadata_mask}) do
|
@spec to_binary(t()) :: <<_::192>>
|
||||||
<<2::16, 24::16, 0::size(4)-unit(8), metadata::64, metadata_mask::64>>
|
def to_binary(%WriteMetadata{value: value, mask: mask}) do
|
||||||
|
<<2::16, 24::16, 0::size(4)-unit(8), value::64, mask::64>>
|
||||||
end
|
end
|
||||||
|
|
||||||
def read(<<2::16, 24::16, _::size(4)-unit(8), metadata::64, metadata_mask::64>>) do
|
@spec read(<<_::192>>) :: t()
|
||||||
%WriteMetadata{metadata: metadata, metadata_mask: metadata_mask}
|
def read(<<2::16, 24::16, _::size(4)-unit(8), value::64, mask::64>>) do
|
||||||
|
%WriteMetadata{value: value, mask: mask}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
35
test/ofp_instruction_test.exs
Normal file
35
test/ofp_instruction_test.exs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
defmodule OfpInstructionTest do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Openflow
|
||||||
|
|
||||||
|
alias Openflow.Instruction.{
|
||||||
|
ApplyActions,
|
||||||
|
WriteActions,
|
||||||
|
ClearActions,
|
||||||
|
GotoTable,
|
||||||
|
WriteMetadata,
|
||||||
|
Meter,
|
||||||
|
Experimenter
|
||||||
|
}
|
||||||
|
|
||||||
|
describe "Openflow.Instruction" do
|
||||||
|
test "with all instructions parse and generate" do
|
||||||
|
instructions = [
|
||||||
|
ApplyActions.new([Openflow.Action.Output.new(:controller)]),
|
||||||
|
WriteActions.new([Openflow.Action.Output.new(5)]),
|
||||||
|
ClearActions.new(),
|
||||||
|
GotoTable.new(10),
|
||||||
|
WriteMetadata.new(value: 100, mask: 0xFFFFFFFFFFFFFFFF),
|
||||||
|
Meter.new(100),
|
||||||
|
Experimenter.new(0xCAFEBABE, "hogehoge"),
|
||||||
|
Experimenter.new(0xCAFEBABE)
|
||||||
|
]
|
||||||
|
|
||||||
|
instructions
|
||||||
|
|> Openflow.Instruction.to_binary()
|
||||||
|
|> Openflow.Instruction.read()
|
||||||
|
|> Kernel.==(instructions)
|
||||||
|
|> assert()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue