quality: Add test cases for openflow actions
This commit is contained in:
parent
2c0a283932
commit
84a827eea1
5 changed files with 188 additions and 88 deletions
|
|
@ -25,7 +25,31 @@ defmodule Openflow.Action.NxController2 do
|
|||
alias __MODULE__
|
||||
alias Openflow.Action.Experimenter
|
||||
|
||||
def new(options \\ []) do
|
||||
@type max_len :: pos_integer() | :max | :no_buffer
|
||||
@type packet_in_reason ::
|
||||
:no_match | :action | :invalid_ttl | :action_set | :group | :packet_out
|
||||
@type meter_id :: pos_integer() | :max | :slowpath | :controller | :all
|
||||
|
||||
@type t :: %NxController2{
|
||||
max_len: max_len(),
|
||||
id: non_neg_integer(),
|
||||
reason: packet_in_reason(),
|
||||
userdata: binary(),
|
||||
pause: boolean(),
|
||||
meter_id: meter_id()
|
||||
}
|
||||
|
||||
@spec new(
|
||||
max_len: max_len(),
|
||||
id: non_neg_integer(),
|
||||
reason: packet_in_reason(),
|
||||
userdata: binary(),
|
||||
pause: boolean(),
|
||||
meter_id: meter_id()
|
||||
) :: t()
|
||||
def new(options \\ [])
|
||||
|
||||
def new(options) when is_list(options) do
|
||||
%NxController2{
|
||||
max_len: options[:max_len] || :no_buffer,
|
||||
id: options[:id] || 0,
|
||||
|
|
|
|||
|
|
@ -15,35 +15,46 @@ defmodule Openflow.Action.NxNat do
|
|||
alias __MODULE__
|
||||
alias Openflow.Action.Experimenter
|
||||
|
||||
def new(options \\ []) do
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
ipv4_min = Keyword.get(options, :ipv4_min)
|
||||
ipv4_max = Keyword.get(options, :ipv4_max)
|
||||
ipv6_min = Keyword.get(options, :ipv6_min)
|
||||
ipv6_max = Keyword.get(options, :ipv6_max)
|
||||
proto_min = Keyword.get(options, :proto_min)
|
||||
proto_max = Keyword.get(options, :proto_max)
|
||||
@type in_addr :: :inet.ip4_address()
|
||||
@type in6_addr :: :inet.ip6_address()
|
||||
@type port_number :: :inet.port_number()
|
||||
@type flag :: :src | :dst | :persistent | :protocol_hash | :protocol_random
|
||||
@type nat_range :: :ipv4_min | :ipv4_max | :ipv6_min | :ipv6_max | :proto_min | :proto_max
|
||||
@type t :: %NxNat{
|
||||
flags: [flag()],
|
||||
ipv4_min: in_addr(),
|
||||
ipv4_max: in_addr(),
|
||||
ipv6_min: in6_addr(),
|
||||
ipv6_max: in6_addr(),
|
||||
proto_min: port_number(),
|
||||
proto_max: port_number()
|
||||
}
|
||||
|
||||
@spec new(
|
||||
flags: [flag()],
|
||||
ipv4_min: in_addr(),
|
||||
ipv4_max: in_addr(),
|
||||
ipv6_min: in6_addr(),
|
||||
ipv6_max: in6_addr(),
|
||||
proto_min: port_number(),
|
||||
proto_max: port_number()
|
||||
) :: t()
|
||||
def new(options \\ []) do
|
||||
%NxNat{
|
||||
flags: flags,
|
||||
ipv4_min: ipv4_min,
|
||||
ipv4_max: ipv4_max,
|
||||
ipv6_min: ipv6_min,
|
||||
ipv6_max: ipv6_max,
|
||||
proto_min: proto_min,
|
||||
proto_max: proto_max
|
||||
flags: options[:flags] || [],
|
||||
ipv4_min: options[:ipv4_min],
|
||||
ipv4_max: options[:ipv4_max],
|
||||
ipv6_min: options[:ipv6_min],
|
||||
ipv6_max: options[:ipv6_max],
|
||||
proto_min: options[:proto_min],
|
||||
proto_max: options[:proto_max]
|
||||
}
|
||||
end
|
||||
|
||||
@spec to_binary(t()) :: binary()
|
||||
def to_binary(%NxNat{flags: flags} = nat) do
|
||||
flags_int = Openflow.Enums.flags_to_int(flags, :nx_nat_flags)
|
||||
|
||||
range_flags =
|
||||
nat
|
||||
|> get_ranges
|
||||
|> Openflow.Enums.flags_to_int(:nx_nat_range)
|
||||
|> Openflow.Enums.int_to_flags(:nx_nat_range)
|
||||
|
||||
range_flags = get_range_flags(nat)
|
||||
ranges_bin = encode_ranges("", range_flags, nat)
|
||||
range_flags_int = Openflow.Enums.flags_to_int(range_flags, :nx_nat_range)
|
||||
|
||||
|
|
@ -57,6 +68,7 @@ defmodule Openflow.Action.NxNat do
|
|||
>>)
|
||||
end
|
||||
|
||||
@spec read(binary()) :: t()
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<0::size(2)-unit(8), flags_int::16, range_flags_int::16, ranges_bin::bytes>> = body
|
||||
flags = Openflow.Enums.int_to_flags(flags_int, :nx_nat_flags)
|
||||
|
|
@ -66,81 +78,95 @@ defmodule Openflow.Action.NxNat do
|
|||
|
||||
# private functions
|
||||
|
||||
defp get_ranges(nat) do
|
||||
nat
|
||||
|> Map.from_struct()
|
||||
|> Map.delete(:flags)
|
||||
|> Enum.map(fn {k, v} -> if(not is_nil(v), do: k, else: nil) end)
|
||||
|> Enum.filter(fn v -> not is_nil(v) end)
|
||||
@range_keys [:ipv4_min, :ipv4_max, :ipv6_min, :ipv6_max, :proto_min, :proto_max]
|
||||
|
||||
@spec get_range_flags(t()) :: [nat_range()]
|
||||
defp get_range_flags(nat) do
|
||||
@range_keys
|
||||
|> Enum.reduce([], fn
|
||||
key, acc when key in @range_keys ->
|
||||
if not is_nil(Map.get(nat, key)), do: [key | acc], else: acc
|
||||
end)
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
@spec encode_ranges(binary(), [nat_range()], t()) :: binary()
|
||||
defp encode_ranges(acc, [], _nat), do: acc
|
||||
|
||||
defp encode_ranges(acc, [range | rest], nat) do
|
||||
cond do
|
||||
range == :ipv4_min or range == :ipv4_max ->
|
||||
case Map.get(nat, range) do
|
||||
{a1, a2, a3, a4} ->
|
||||
encode_ranges(<<acc::bytes, a1, a2, a3, a4>>, rest, nat)
|
||||
|
||||
"" ->
|
||||
encode_ranges(<<acc::bytes>>, rest, nat)
|
||||
end
|
||||
|
||||
range == :ipv6_min or range == :ipv6_max ->
|
||||
case Map.get(nat, range) do
|
||||
{a1, a2, a3, a4, a5, a6, a7, a8} ->
|
||||
encode_ranges(
|
||||
<<acc::bytes, a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16>>,
|
||||
rest,
|
||||
nat
|
||||
)
|
||||
|
||||
"" ->
|
||||
encode_ranges(<<acc::bytes>>, rest, nat)
|
||||
end
|
||||
|
||||
range == :proto_min or range == :proto_max ->
|
||||
case Map.get(nat, range) do
|
||||
proto when is_integer(proto) and proto in 1..0xFFFF ->
|
||||
encode_ranges(<<acc::bytes, proto::16>>, rest, nat)
|
||||
|
||||
_ ->
|
||||
encode_ranges(<<acc::bytes>>, rest, nat)
|
||||
end
|
||||
end
|
||||
defp encode_ranges(acc, [:ipv4_min | rest], %NxNat{ipv4_min: {a1, a2, a3, a4}} = nat) do
|
||||
encode_ranges(<<acc::bytes, a1, a2, a3, a4>>, rest, nat)
|
||||
end
|
||||
|
||||
defp encode_ranges(acc, [:ipv4_max | rest], %NxNat{ipv4_max: {a1, a2, a3, a4}} = nat) do
|
||||
encode_ranges(<<acc::bytes, a1, a2, a3, a4>>, rest, nat)
|
||||
end
|
||||
|
||||
defp encode_ranges(
|
||||
acc,
|
||||
[:ipv6_min | rest],
|
||||
%NxNat{ipv6_min: {a1, a2, a3, a4, a5, a6, a7, a8}} = nat
|
||||
) do
|
||||
encode_ranges(
|
||||
<<acc::bytes, a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16>>,
|
||||
rest,
|
||||
nat
|
||||
)
|
||||
end
|
||||
|
||||
defp encode_ranges(
|
||||
acc,
|
||||
[:ipv6_max | rest],
|
||||
%NxNat{ipv6_max: {a1, a2, a3, a4, a5, a6, a7, a8}} = nat
|
||||
) do
|
||||
encode_ranges(
|
||||
<<acc::bytes, a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16>>,
|
||||
rest,
|
||||
nat
|
||||
)
|
||||
end
|
||||
|
||||
defp encode_ranges(acc, [:proto_min | rest], %NxNat{proto_min: proto} = nat)
|
||||
when is_integer(proto) do
|
||||
encode_ranges(<<acc::bytes, proto::16>>, rest, nat)
|
||||
end
|
||||
|
||||
defp encode_ranges(acc, [:proto_max | rest], %NxNat{proto_max: proto} = nat)
|
||||
when is_integer(proto) do
|
||||
encode_ranges(<<acc::bytes, proto::16>>, rest, nat)
|
||||
end
|
||||
|
||||
@spec decode_ranges(t(), [nat_range()], binary()) :: t()
|
||||
defp decode_ranges(nat, [], _), do: nat
|
||||
|
||||
defp decode_ranges(nat, [range | ranges], bin) do
|
||||
cond do
|
||||
range == :ipv4_min or range == :ipv4_max ->
|
||||
case bin do
|
||||
<<a1, a2, a3, a4, rest::bytes>> ->
|
||||
decode_ranges(struct(nat, %{range => {a1, a2, a3, a4}}), ranges, rest)
|
||||
defp decode_ranges(acc, [:ipv4_min | rest], <<a1, a2, a3, a4, binary::bytes>>) do
|
||||
decode_ranges(%{acc | ipv4_min: {a1, a2, a3, a4}}, rest, binary)
|
||||
end
|
||||
|
||||
rest ->
|
||||
decode_ranges(struct(nat, %{range => ""}), ranges, rest)
|
||||
end
|
||||
defp decode_ranges(acc, [:ipv4_max | rest], <<a1, a2, a3, a4, binary::bytes>>) do
|
||||
decode_ranges(%{acc | ipv4_max: {a1, a2, a3, a4}}, rest, binary)
|
||||
end
|
||||
|
||||
range == :ipv6_min or range == :ipv6_max ->
|
||||
case bin do
|
||||
<<a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16, rest::bytes>> ->
|
||||
decode_ranges(struct(nat, %{range => {a1, a2, a3, a4, a5, a6, a7, a8}}), ranges, rest)
|
||||
defp decode_ranges(
|
||||
acc,
|
||||
[:ipv6_min | rest],
|
||||
<<a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16, binary::bytes>>
|
||||
) do
|
||||
decode_ranges(%{acc | ipv6_min: {a1, a2, a3, a4, a5, a6, a7, a8}}, rest, binary)
|
||||
end
|
||||
|
||||
rest ->
|
||||
decode_ranges(struct(nat, %{range => ""}), ranges, rest)
|
||||
end
|
||||
defp decode_ranges(
|
||||
acc,
|
||||
[:ipv6_max | rest],
|
||||
<<a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16, binary::bytes>>
|
||||
) do
|
||||
decode_ranges(%{acc | ipv6_max: {a1, a2, a3, a4, a5, a6, a7, a8}}, rest, binary)
|
||||
end
|
||||
|
||||
range == :proto_min or range == :proto_max ->
|
||||
case bin do
|
||||
<<proto::16, rest::bytes>> when proto in 1..0xFFFF ->
|
||||
decode_ranges(struct(nat, %{range => proto}), ranges, rest)
|
||||
defp decode_ranges(acc, [:proto_min | rest], <<proto::16, binary::bytes>>) do
|
||||
decode_ranges(%{acc | proto_min: proto}, rest, binary)
|
||||
end
|
||||
|
||||
rest ->
|
||||
decode_ranges(struct(nat, %{range => ""}), ranges, rest)
|
||||
end
|
||||
end
|
||||
defp decode_ranges(acc, [:proto_max | rest], <<proto::16, binary::bytes>>) do
|
||||
decode_ranges(%{acc | proto_max: proto}, rest, binary)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue