Openflow parser
This commit is contained in:
parent
70b0d8919e
commit
fc02a678de
338 changed files with 9081 additions and 0 deletions
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where 3rd-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
21
README.md
Normal file
21
README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Tres
|
||||
|
||||
**TODO: Add description**
|
||||
|
||||
## Installation
|
||||
|
||||
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||
by adding `tres` to your list of dependencies in `mix.exs`:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:tres, "~> 0.1.0"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
|
||||
be found at [https://hexdocs.pm/tres](https://hexdocs.pm/tres).
|
||||
|
||||
16
config/config.exs
Normal file
16
config/config.exs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# This file is responsible for configuring your application
|
||||
# and its dependencies with the aid of the Mix.Config module.
|
||||
use Mix.Config
|
||||
|
||||
config :tres,
|
||||
callback_module: Tres.ExampleHandler,
|
||||
max_connections: 10,
|
||||
num_acceptors: 10,
|
||||
protocol: :tcp,
|
||||
port: 6653
|
||||
|
||||
config :logger,
|
||||
level: :info,
|
||||
format: "$date $time [$level] $metadata$message\n",
|
||||
metadata: [:application],
|
||||
handle_otp_reports: true
|
||||
50
lib/openflow.ex
Normal file
50
lib/openflow.ex
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
defmodule Openflow do
|
||||
@moduledoc "OpenFlow Protocol format codec"
|
||||
|
||||
@ofp_header_size 8
|
||||
|
||||
@spec read(binary()) :: {:ok, map()} | {:error, :binary_too_small}
|
||||
def read(binary)
|
||||
when byte_size(binary) < @ofp_header_size do
|
||||
{:error, :binary_too_small}
|
||||
end
|
||||
def read(<<_v::8, _t::8, len::16, _x::32, _r::bytes>> = binary)
|
||||
when byte_size(binary) < len do
|
||||
{:error, :binary_too_small}
|
||||
end
|
||||
def read(<<ver::8, type::8, len::16, xid::32, binary2::bytes>>) do
|
||||
body_len = len - @ofp_header_size
|
||||
<<body_bin::bytes-size(body_len), rest::bytes>> = binary2
|
||||
|
||||
result = type
|
||||
|> Openflow.Enums.to_atom(:openflow_codec)
|
||||
|> do_read(body_bin)
|
||||
|
||||
case result do
|
||||
{:ok, struct} -> {:ok, %{struct|version: ver, xid: xid}, rest}
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
def to_binary(%{__struct__: encoder, version: version, xid: xid} = msg) do
|
||||
case encoder.to_binary(msg) do
|
||||
body_bin when is_binary(body_bin) ->
|
||||
length = @ofp_header_size + byte_size(body_bin)
|
||||
<<version::8, (encoder.ofp_type)::8, length::16, xid::32, body_bin::bytes>>
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp do_read({:error, reason}, _) do
|
||||
{:error, reason}
|
||||
end
|
||||
defp do_read(decoder, body_bin) do
|
||||
case decoder.read(body_bin) do
|
||||
{:error, reason} -> {:error, reason}
|
||||
result when is_map(result) -> {:ok, result}
|
||||
end
|
||||
end
|
||||
end
|
||||
1
lib/openflow/.#nx_packet_in2.ex
Symbolic link
1
lib/openflow/.#nx_packet_in2.ex
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
shun159@shun159.5674:1510580208
|
||||
29
lib/openflow/action.ex
Normal file
29
lib/openflow/action.ex
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
defmodule Openflow.Action do
|
||||
|
||||
def read(action_bin) do
|
||||
do_read([], action_bin)
|
||||
end
|
||||
|
||||
def to_binary(actions) when is_list(actions) do
|
||||
to_binary(<<>>, actions)
|
||||
end
|
||||
def to_binary(action) do
|
||||
to_binary([action])
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp do_read(acc, <<>>), do: Enum.reverse(acc)
|
||||
defp do_read(acc, <<0::32, _::bytes>>), do: Enum.reverse(acc)
|
||||
defp do_read(acc, <<type::16, length::16, _::bytes>> = binary) do
|
||||
<<action_bin::size(length)-bytes, rest::bytes>> = binary
|
||||
codec = Openflow.Enums.to_atom(type, :action_type)
|
||||
do_read([codec.read(action_bin)|acc], rest)
|
||||
end
|
||||
|
||||
defp to_binary(acc, []), do: acc
|
||||
defp to_binary(acc, [action|rest]) do
|
||||
codec = action.__struct__
|
||||
to_binary(<<acc::bytes, (codec.to_binary(action))::bytes>>, rest)
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/copy_ttl_in.ex
Normal file
19
lib/openflow/actions/copy_ttl_in.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.CopyTtlIn do
|
||||
defstruct([])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 12
|
||||
|
||||
def new do
|
||||
%CopyTtlIn{}
|
||||
end
|
||||
|
||||
def to_binary(%CopyTtlIn{}) do
|
||||
<<12::16, 8::16, 0::size(4)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<12::16, 8::16, _::size(4)-unit(8)>>) do
|
||||
%CopyTtlIn{}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/copy_ttl_out.ex
Normal file
19
lib/openflow/actions/copy_ttl_out.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.CopyTtlOut do
|
||||
defstruct([])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 11
|
||||
|
||||
def new do
|
||||
%CopyTtlOut{}
|
||||
end
|
||||
|
||||
def to_binary(%CopyTtlOut{}) do
|
||||
<<11::16, 8::16, 0::size(4)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<11::16, 8::16, _::size(4)-unit(8)>>) do
|
||||
%CopyTtlOut{}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/dec_mpls_ttl.ex
Normal file
19
lib/openflow/actions/dec_mpls_ttl.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.DecMplsTtl do
|
||||
defstruct([])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 16
|
||||
|
||||
def new do
|
||||
%DecMplsTtl{}
|
||||
end
|
||||
|
||||
def to_binary(%DecMplsTtl{}) do
|
||||
<<16::16, 8::16, 0::size(4)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<16::16, 8::16, _::size(4)-unit(8)>>) do
|
||||
%DecMplsTtl{}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/dec_nw_ttl.ex
Normal file
19
lib/openflow/actions/dec_nw_ttl.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.DecNwTtl do
|
||||
defstruct([])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 24
|
||||
|
||||
def new do
|
||||
%DecNwTtl{}
|
||||
end
|
||||
|
||||
def to_binary(%DecNwTtl{}) do
|
||||
<<24::16, 8::16, 0::size(4)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<24::16, 8::16, _::size(4)-unit(8)>>) do
|
||||
%DecNwTtl{}
|
||||
end
|
||||
end
|
||||
32
lib/openflow/actions/experimenter.ex
Normal file
32
lib/openflow/actions/experimenter.ex
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
defmodule Openflow.Action.Experimenter do
|
||||
defstruct(exp_id: 0, data: "")
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
@experimter_size 8
|
||||
|
||||
def ofpat, do: 0xffff
|
||||
|
||||
def new(exp_id, data \\ "") do
|
||||
%Experimenter{exp_id: exp_id, data: data}
|
||||
end
|
||||
|
||||
def to_binary(%Experimenter{exp_id: exp_id, data: data}) do
|
||||
length = @experimter_size + byte_size(data)
|
||||
<<0xffff::16, length::16, exp_id::32, data::bytes>>
|
||||
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) ->
|
||||
%Experimenter{exp_id: exp_id, data: <<exp_type::16, data::bytes>>}
|
||||
vendor when is_atom(vendor) ->
|
||||
case Openflow.Utils.get_enum(exp_type, vendor) do
|
||||
codec when is_atom(codec) ->
|
||||
codec.read(<<exp_id::32, exp_type::16, data::bytes>>)
|
||||
exp_type when is_integer(exp_type) ->
|
||||
%Experimenter{exp_id: exp_id, data: <<exp_type::16, data::bytes>>}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/group.ex
Normal file
19
lib/openflow/actions/group.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.Group do
|
||||
defstruct(id: 0)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 22
|
||||
|
||||
def new(id) do
|
||||
%Group{id: id}
|
||||
end
|
||||
|
||||
def to_binary(%Group{id: id}) do
|
||||
<<22::16, 8::16, id::32>>
|
||||
end
|
||||
|
||||
def read(<<22::16, 8::16, id::32>>) do
|
||||
%Group{id: id}
|
||||
end
|
||||
end
|
||||
80
lib/openflow/actions/nx_bundle.ex
Normal file
80
lib/openflow/actions/nx_bundle.ex
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
defmodule Openflow.Action.NxBundle do
|
||||
defstruct(
|
||||
algorithm: :active_backup,
|
||||
hash_field: :eth_src,
|
||||
basis: 0,
|
||||
slave_type: :nx_in_port,
|
||||
n_slaves: 0,
|
||||
slaves: []
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 12
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
hash_field = Keyword.get(options, :hash_field, :eth_src)
|
||||
basis = Keyword.get(options, :basis, 0)
|
||||
alg = Keyword.get(options, :algorithm, :active_backup)
|
||||
slaves = Keyword.get(options, :slaves, [])
|
||||
%NxBundle{algorithm: alg,
|
||||
hash_field: hash_field,
|
||||
basis: basis,
|
||||
n_slaves: length(slaves),
|
||||
slaves: slaves}
|
||||
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)
|
||||
body = <<alg_int::16, hash_field_int::16, basis::16,
|
||||
slave_type_bin::4-bytes, n_slaves::16, 0::16, 0::size(4)-unit(8), 0::32,
|
||||
slaves_bin::bytes>>
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<alg_int::16, hash_field_int::16, basis::16,
|
||||
slave_type_bin::4-bytes, n_slaves::16, _::16, _::32, _::32, rest::bytes>> = body
|
||||
slave_len = n_slaves * 2
|
||||
<<slaves_bin::size(slave_len)-bytes, _::bytes>> = rest
|
||||
alg = Openflow.Enums.to_atom(alg_int, :nx_bd_algorithm)
|
||||
hash_field = Openflow.Enums.to_atom(hash_field_int, :nx_hash_fields)
|
||||
slave_type = Openflow.Match.codec_header(slave_type_bin)
|
||||
slaves = codec_slaves(slaves_bin)
|
||||
n_slaves = length(slaves)
|
||||
%NxBundle{algorithm: alg,
|
||||
hash_field: hash_field,
|
||||
basis: basis,
|
||||
slave_type: slave_type,
|
||||
n_slaves: n_slaves,
|
||||
slaves: slaves}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp codec_slaves(slaves) when is_list(slaves) do
|
||||
slaves1 = for slave <- slaves do
|
||||
slave_int = Openflow.Utils.get_enum(slave, :openflow10_port_no)
|
||||
<<slave_int::16>>
|
||||
end
|
||||
Enum.join(slaves1, "")
|
||||
end
|
||||
defp codec_slaves(slaves) when is_binary(slaves) do
|
||||
for <<slave_int::16 <- slaves>> do
|
||||
Openflow.Utils.get_enum(slave_int, :openflow10_port_no)
|
||||
end
|
||||
end
|
||||
end
|
||||
102
lib/openflow/actions/nx_bundle_load.ex
Normal file
102
lib/openflow/actions/nx_bundle_load.ex
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
defmodule Openflow.Action.NxBundleLoad do
|
||||
import Bitwise
|
||||
|
||||
defstruct(
|
||||
algorithm: :active_backup,
|
||||
hash_field: :eth_src,
|
||||
basis: 0,
|
||||
slave_type: :nx_in_port,
|
||||
n_slaves: 0,
|
||||
slaves: [],
|
||||
offset: 0,
|
||||
n_bits: 0,
|
||||
dst_field: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 13
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
hash_field = Keyword.get(options, :hash_field, :eth_src)
|
||||
basis = Keyword.get(options, :basis, 0)
|
||||
alg = Keyword.get(options, :algorithm, :active_backup)
|
||||
slaves = Keyword.get(options, :slaves, [])
|
||||
dst_field = Keyword.get(options, :dst_field)
|
||||
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)
|
||||
%NxBundleLoad{algorithm: alg,
|
||||
hash_field: hash_field,
|
||||
basis: basis,
|
||||
n_slaves: length(slaves),
|
||||
slaves: slaves,
|
||||
offset: ofs,
|
||||
n_bits: n_bits,
|
||||
dst_field: dst_field}
|
||||
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)
|
||||
body = <<alg_int::16, hash_field_int::16, basis::16,
|
||||
slave_type_bin::4-bytes, n_slaves::16, ofs_nbits::16,
|
||||
dst_field_bin::4-bytes, 0::32, slaves_bin::bytes>>
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<alg_int::16, hash_field_int::16, basis::16,
|
||||
slave_type_bin::4-bytes, n_slaves::16, ofs::10, n_bits::6,
|
||||
dst_field_bin::4-bytes, _reserved::32, rest::bytes>> = body
|
||||
slave_len = n_slaves * 2
|
||||
<<slaves_bin::size(slave_len)-bytes, _::bytes>> = rest
|
||||
alg = Openflow.Enums.to_atom(alg_int, :nx_bd_algorithm)
|
||||
hash_field = Openflow.Enums.to_atom(hash_field_int, :nx_hash_fields)
|
||||
slave_type = Openflow.Match.codec_header(slave_type_bin)
|
||||
slaves = codec_slaves(slaves_bin)
|
||||
n_slaves = length(slaves)
|
||||
dst_field = Openflow.Match.codec_header(dst_field_bin)
|
||||
%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 + 1,
|
||||
dst_field: dst_field}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp codec_slaves(slaves) when is_list(slaves) do
|
||||
slaves1 = for slave <- slaves do
|
||||
slave_int = Openflow.Utils.get_enum(slave, :openflow10_port_no)
|
||||
<<slave_int::16>>
|
||||
end
|
||||
Enum.join(slaves1, "")
|
||||
end
|
||||
defp codec_slaves(slaves) when is_binary(slaves) do
|
||||
for <<slave_int::16 <- slaves>> do
|
||||
Openflow.Utils.get_enum(slave_int, :openflow10_port_no)
|
||||
end
|
||||
end
|
||||
end
|
||||
28
lib/openflow/actions/nx_clone.ex
Normal file
28
lib/openflow/actions/nx_clone.ex
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
defmodule Openflow.Action.NxClone do
|
||||
defstruct(
|
||||
actions: []
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 42
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(actions \\ []) do
|
||||
%NxClone{actions: actions}
|
||||
end
|
||||
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, 0::size(6)-unit(8), actions_bin::bytes>>) do
|
||||
actions = Openflow.Action.read(actions_bin)
|
||||
%NxClone{actions: actions}
|
||||
end
|
||||
end
|
||||
28
lib/openflow/actions/nx_conjunction.ex
Normal file
28
lib/openflow/actions/nx_conjunction.ex
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
defmodule Openflow.Action.NxConjunction do
|
||||
defstruct(
|
||||
clause: 0,
|
||||
n_clauses: 0,
|
||||
id: 0
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 34
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
clause = Keyword.get(options, :clause, 0)
|
||||
n_clauses = Keyword.get(options, :n_clauses, 0)
|
||||
id = Keyword.get(options, :id, 0)
|
||||
%NxConjunction{clause: clause, n_clauses: n_clauses, id: id}
|
||||
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>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, clause::8, n_clauses::8, id::32>>) do
|
||||
%NxConjunction{clause: clause, n_clauses: n_clauses, id: id}
|
||||
end
|
||||
end
|
||||
88
lib/openflow/actions/nx_conntrack.ex
Normal file
88
lib/openflow/actions/nx_conntrack.ex
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
defmodule Openflow.Action.NxConntrack do
|
||||
import Bitwise
|
||||
|
||||
defstruct(
|
||||
flags: [],
|
||||
zone_src: nil,
|
||||
zone_imm: 0,
|
||||
zone_offset: nil,
|
||||
zone_n_bits: nil,
|
||||
recirc_table: 255,
|
||||
alg: 0,
|
||||
exec: []
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 35
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options \\ []) do
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
zone_src = Keyword.get(options, :zone_src)
|
||||
zone_ofs = Keyword.get(options, :zone_offset)
|
||||
zone_n_bits = Keyword.get(options, :zone_n_bits)
|
||||
zone_imm = Keyword.get(options, :zone_imm, 0)
|
||||
recirc_table = Keyword.get(options, :recirc_table, 255)
|
||||
alg = Keyword.get(options, :alg, 0)
|
||||
exec = Keyword.get(options, :exec, [])
|
||||
%NxConntrack{
|
||||
flags: flags,
|
||||
zone_src: zone_src,
|
||||
zone_imm: zone_imm,
|
||||
zone_offset: zone_ofs,
|
||||
zone_n_bits: zone_n_bits,
|
||||
recirc_table: recirc_table,
|
||||
alg: alg,
|
||||
exec: exec
|
||||
}
|
||||
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)
|
||||
{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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, flags_int::16,
|
||||
src_bin::4-bytes, ofs_nbits::16-bits, recirc_table::8,
|
||||
_::size(3)-unit(8), alg::16, exec_bin::bytes>>) do
|
||||
flags = Openflow.Enums.int_to_flags(flags_int, :nx_conntrack_flags)
|
||||
exec = Openflow.Action.read(exec_bin)
|
||||
ct = %NxConntrack{
|
||||
flags: flags,
|
||||
recirc_table: recirc_table,
|
||||
alg: alg,
|
||||
exec: exec
|
||||
}
|
||||
case src_bin do
|
||||
<<0::32>> ->
|
||||
<<zone_imm::16>> = ofs_nbits
|
||||
%{ct|zone_imm: zone_imm}
|
||||
binary when is_binary(binary) ->
|
||||
zone_src = Openflow.Match.codec_header(binary)
|
||||
<<ofs::10, n_bits::6>> = ofs_nbits
|
||||
%{ct|zone_src: zone_src, zone_offset: ofs, zone_n_bits: n_bits + 1}
|
||||
end
|
||||
end
|
||||
end
|
||||
32
lib/openflow/actions/nx_controller.ex
Normal file
32
lib/openflow/actions/nx_controller.ex
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
defmodule Openflow.Action.NxController do
|
||||
defstruct(
|
||||
max_len: :no_buffer,
|
||||
id: 0,
|
||||
reason: :action
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 20
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
max_len = Keyword.get(options, :max_len, :no_buffer)
|
||||
controller_id = Keyword.get(options, :id, 0)
|
||||
reason = Keyword.get(options, :reason, :action)
|
||||
%NxController{max_len: max_len, id: controller_id, reason: reason}
|
||||
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)
|
||||
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>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, max_len_int::16, controller_id::16, reason_int::8, _::bytes>>) do
|
||||
max_len = Openflow.Utils.get_enum(max_len_int, :controller_max_len)
|
||||
reason = Openflow.Enums.to_atom(reason_int, :packet_in_reason)
|
||||
%NxController{max_len: max_len, id: controller_id, reason: reason}
|
||||
end
|
||||
end
|
||||
119
lib/openflow/actions/nx_controller2.ex
Normal file
119
lib/openflow/actions/nx_controller2.ex
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
defmodule Openflow.Action.NxController2 do
|
||||
defstruct(
|
||||
max_len: :no_buffer,
|
||||
id: 0,
|
||||
reason: :action,
|
||||
userdata: "",
|
||||
pause: false
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 37
|
||||
|
||||
@prop_header_size 4
|
||||
|
||||
@prop_max_len 0
|
||||
@prop_ctl_id 1
|
||||
@prop_reason 2
|
||||
@prop_userdata 3
|
||||
@prop_pause 4
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
max_len = Keyword.get(options, :max_len, :no_buffer)
|
||||
controller_id = Keyword.get(options, :id, 0)
|
||||
reason = Keyword.get(options, :reason, :action)
|
||||
userdata = Keyword.get(options, :userdata)
|
||||
pause = Keyword.get(options, :pause, false)
|
||||
%NxController2{max_len: max_len,
|
||||
id: controller_id,
|
||||
reason: reason,
|
||||
userdata: userdata,
|
||||
pause: pause}
|
||||
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 = <<ext_header::bytes, props_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>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, 0::size(6)-unit(8), body::bytes>>) do
|
||||
%NxController2{}
|
||||
|> decode_prop(body)
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp get_prop_key(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)
|
||||
end
|
||||
|
||||
defp encode_prop(acc, [], _ctl), do: acc
|
||||
defp encode_prop(acc, [prop|rest], ctl) do
|
||||
value = Map.get(ctl, prop)
|
||||
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)>>
|
||||
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)>>
|
||||
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)>>
|
||||
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)>>
|
||||
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)>>
|
||||
true ->
|
||||
""
|
||||
end
|
||||
encode_prop(<<acc::bytes, prop_bin::bytes>>, rest, ctl)
|
||||
end
|
||||
|
||||
defp decode_prop(ctl, ""), do: ctl
|
||||
defp decode_prop(ctl, <<prop_type_int::16, _::bytes>> = bin) do
|
||||
prop_type = Openflow.Enums.to_atom(prop_type_int, :nx_action_controller2_prop_type)
|
||||
case prop_type do
|
||||
:max_len ->
|
||||
<<@prop_max_len::16, _prop_length::16, max_len_int::16, _::size(2)-unit(8), rest::bytes>> = bin
|
||||
max_len = Openflow.Utils.get_enum(max_len_int, :controller_max_len)
|
||||
decode_prop(struct(ctl, %{max_len: max_len}), rest)
|
||||
:controller_id ->
|
||||
<<@prop_ctl_id::16, _prop_length::16, controller_id::16, _::size(2)-unit(8), rest::bytes>> = bin
|
||||
decode_prop(struct(ctl, %{controller_id: controller_id}), rest)
|
||||
: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)
|
||||
<<userdata::size(userdata_len)-bytes, _::size(padding_length)-unit(8), rest::bytes>> = 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)
|
||||
end
|
||||
end
|
||||
end
|
||||
21
lib/openflow/actions/nx_ct_clear.ex
Normal file
21
lib/openflow/actions/nx_ct_clear.ex
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
defmodule Openflow.Action.NxCtClear do
|
||||
defstruct([])
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 43
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, _::16, _::size(4)-unit(8)>>) do
|
||||
%NxCtClear{}
|
||||
end
|
||||
end
|
||||
21
lib/openflow/actions/nx_dec_mpls_ttl.ex
Normal file
21
lib/openflow/actions/nx_dec_mpls_ttl.ex
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
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
|
||||
21
lib/openflow/actions/nx_dec_ttl.ex
Normal file
21
lib/openflow/actions/nx_dec_ttl.ex
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
defmodule Openflow.Action.NxDecTtl do
|
||||
defstruct([])
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 18
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, _::16, _::size(4)-unit(8)>>) do
|
||||
%NxDecTtl{}
|
||||
end
|
||||
end
|
||||
31
lib/openflow/actions/nx_dec_ttl_cnt_ids.ex
Normal file
31
lib/openflow/actions/nx_dec_ttl_cnt_ids.ex
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
defmodule Openflow.Action.NxDecTtlCntIds do
|
||||
defstruct(ids: [])
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 21
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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: <<id::16>>), "")
|
||||
padding = Openflow.Utils.padding(n_controllers, 8)
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, n_controllers::16, body::bitstring>>) do
|
||||
n_controllers_len = n_controllers * 16
|
||||
<<0::size(4)-unit(8), ids_bin::size(n_controllers_len)-bits, _::bitstring>> = body
|
||||
ids = for <<id::16 <- ids_bin>>, do: id
|
||||
%NxDecTtlCntIds{ids: ids}
|
||||
end
|
||||
end
|
||||
21
lib/openflow/actions/nx_exit.ex
Normal file
21
lib/openflow/actions/nx_exit.ex
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
defmodule Openflow.Action.NxExit do
|
||||
defstruct([])
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 17
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, 0::48>>) do
|
||||
%NxExit{}
|
||||
end
|
||||
end
|
||||
26
lib/openflow/actions/nx_fin_timeout.ex
Normal file
26
lib/openflow/actions/nx_fin_timeout.ex
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
defmodule Openflow.Action.NxFinTimeout do
|
||||
defstruct(
|
||||
idle_timeout: 0,
|
||||
hard_timeout: 0
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 19
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
fin_idle = Keyword.get(options, :idle_timeout, 0)
|
||||
fin_hard = Keyword.get(options, :hard_timeout, 0)
|
||||
%NxFinTimeout{idle_timeout: fin_idle, hard_timeout: fin_hard}
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, fin_idle::16, fin_hard::16, _::size(2)-unit(8)>>) do
|
||||
%NxFinTimeout{idle_timeout: fin_idle, hard_timeout: fin_hard}
|
||||
end
|
||||
end
|
||||
29
lib/openflow/actions/nx_flow_spec.ex
Normal file
29
lib/openflow/actions/nx_flow_spec.ex
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
defmodule Openflow.Action.NxFlowSpec do
|
||||
|
||||
def read(flow_spec_bin) do
|
||||
do_read([], flow_spec_bin)
|
||||
end
|
||||
|
||||
def to_binary(flow_specs) when is_list(flow_specs) do
|
||||
to_binary(<<>>, flow_specs)
|
||||
end
|
||||
def to_binary(flow_spec) do
|
||||
to_binary([flow_spec])
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp do_read(acc, <<>>), do: Enum.reverse(acc)
|
||||
defp do_read(acc, <<0::16, _::bitstring>>), do: Enum.reverse(acc)
|
||||
defp do_read(acc, <<_::2, _::1, type::2, _::bitstring>> = binary) do
|
||||
codec = Openflow.Enums.to_atom(type, :nx_flow_spec_type)
|
||||
{flow_spec, rest} = codec.read(binary)
|
||||
do_read([flow_spec|acc], rest)
|
||||
end
|
||||
|
||||
defp to_binary(acc, []), do: acc
|
||||
defp to_binary(acc, [flow_spec|rest]) do
|
||||
codec = flow_spec.__struct__
|
||||
to_binary(<<acc::bytes, (codec.to_binary(flow_spec))::bytes>>, rest)
|
||||
end
|
||||
end
|
||||
83
lib/openflow/actions/nx_flow_spec_load.ex
Normal file
83
lib/openflow/actions/nx_flow_spec_load.ex
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
defmodule Openflow.Action.NxFlowSpecLoad do
|
||||
defstruct(
|
||||
src: nil,
|
||||
dst: nil,
|
||||
n_bits: 0,
|
||||
src_offset: 0,
|
||||
dst_offset: 0
|
||||
)
|
||||
|
||||
@learn_src_field 0
|
||||
@learn_src_immediate 1
|
||||
@learn_dst 1
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src = Keyword.get(options, :src)
|
||||
dst = Keyword.get(options, :dst)
|
||||
src_ofs = Keyword.get(options, :src_offset, 0)
|
||||
dst_ofs = Keyword.get(options, :dst_offset, 0)
|
||||
default_n_bits = Openflow.Match.Field.n_bits_of(dst)
|
||||
n_bits = Keyword.get(options, :n_bits, default_n_bits)
|
||||
%NxFlowSpecLoad{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs}
|
||||
end
|
||||
|
||||
def to_binary(%NxFlowSpecLoad{} = fsm) do
|
||||
%NxFlowSpecLoad{
|
||||
dst: dst_field,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs
|
||||
} = fsm
|
||||
{src_code, src_bin} = codec_src(fsm)
|
||||
dst_bin = Openflow.Match.codec_header(dst_field)
|
||||
case src_code do
|
||||
@learn_src_immediate ->
|
||||
<<0::2, src_code::1, @learn_dst::2, n_bits::11,
|
||||
src_bin::bytes, dst_bin::4-bytes, dst_ofs::16>>
|
||||
@learn_src_field ->
|
||||
<<0::2, src_code::1, @learn_dst::2, n_bits::11,
|
||||
src_bin::4-bytes, src_ofs::16, dst_bin::4-bytes, dst_ofs::16>>
|
||||
end
|
||||
end
|
||||
|
||||
def read(<<_::2, @learn_src_field::1, @learn_dst::2, n_bits::11, src_bin::4-bytes,
|
||||
src_ofs::16, dst_bin::4-bytes, dst_ofs::16, rest::bitstring>>) do
|
||||
src = Openflow.Match.codec_header(src_bin)
|
||||
dst = Openflow.Match.codec_header(dst_bin)
|
||||
flow_spec = %NxFlowSpecLoad{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs}
|
||||
{flow_spec, rest}
|
||||
end
|
||||
def read(<<_::2, @learn_src_immediate::1, @learn_dst::2, n_bits::11, binary::bitstring>>) do
|
||||
rounded_up_len = Openflow.Utils.pad_length(n_bits, 8)
|
||||
rounded_up_nbits = n_bits + rounded_up_len
|
||||
<<src_bin::size(rounded_up_nbits)-bits, dst_bin::4-bytes, dst_ofs::16, rest::bitstring>> = binary
|
||||
dst = Openflow.Match.codec_header(dst_bin)
|
||||
src = Openflow.Match.Field.codec(src_bin, dst)
|
||||
flow_spec = %NxFlowSpecLoad{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
dst_offset: dst_ofs}
|
||||
{flow_spec, rest}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp codec_src(%NxFlowSpecLoad{src: src_field}) when is_atom(src_field) do
|
||||
src_bin = Openflow.Match.codec_header(src_field)
|
||||
{@learn_src_field, src_bin}
|
||||
end
|
||||
defp codec_src(%NxFlowSpecLoad{src: src, dst: dst_field}) do
|
||||
src_bin = Openflow.Match.Field.codec(src, dst_field)
|
||||
{@learn_src_immediate, src_bin}
|
||||
end
|
||||
end
|
||||
83
lib/openflow/actions/nx_flow_spec_match.ex
Normal file
83
lib/openflow/actions/nx_flow_spec_match.ex
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
defmodule Openflow.Action.NxFlowSpecMatch do
|
||||
defstruct(
|
||||
src: nil,
|
||||
dst: nil,
|
||||
n_bits: 0,
|
||||
src_offset: 0,
|
||||
dst_offset: 0
|
||||
)
|
||||
|
||||
@learn_src_field 0
|
||||
@learn_src_immediate 1
|
||||
@learn_dst 0
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src = Keyword.get(options, :src)
|
||||
dst = Keyword.get(options, :dst)
|
||||
default_n_bits = Openflow.Match.Field.n_bits_of(dst)
|
||||
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)
|
||||
%NxFlowSpecMatch{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs}
|
||||
end
|
||||
|
||||
def to_binary(%NxFlowSpecMatch{} = fsm) do
|
||||
%NxFlowSpecMatch{
|
||||
dst: dst_field,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs
|
||||
} = fsm
|
||||
{src_code, src_bin} = codec_src(fsm)
|
||||
dst_bin = Openflow.Match.codec_header(dst_field)
|
||||
case src_code do
|
||||
@learn_src_immediate ->
|
||||
<<0::2, src_code::1, @learn_dst::2, n_bits::11,
|
||||
src_bin::bytes, dst_bin::4-bytes, dst_ofs::16>>
|
||||
@learn_src_field ->
|
||||
<<0::2, src_code::1, @learn_dst::2, n_bits::11,
|
||||
src_bin::bytes, src_ofs::16, dst_bin::4-bytes, dst_ofs::16>>
|
||||
end
|
||||
end
|
||||
|
||||
def read(<<_::2, @learn_src_field::1, @learn_dst::2, n_bits::11, src_bin::4-bytes,
|
||||
src_ofs::16, dst_bin::4-bytes, dst_ofs::16, rest::bitstring>>) do
|
||||
src = Openflow.Match.codec_header(src_bin)
|
||||
dst = Openflow.Match.codec_header(dst_bin)
|
||||
flow_spec = %NxFlowSpecMatch{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs}
|
||||
{flow_spec, rest}
|
||||
end
|
||||
def read(<<_::2, @learn_src_immediate::1, @learn_dst::2, n_bits::11, binary::bitstring>>) do
|
||||
rounded_up_len = Openflow.Utils.pad_length(n_bits, 8)
|
||||
rounded_up_nbits = n_bits + rounded_up_len
|
||||
<<src_bin::size(rounded_up_nbits)-bits, dst_bin::4-bytes, dst_ofs::16, rest::bitstring>> = binary
|
||||
dst = Openflow.Match.codec_header(dst_bin)
|
||||
src = Openflow.Match.Field.codec(src_bin, dst)
|
||||
flow_spec = %NxFlowSpecMatch{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
dst_offset: dst_ofs}
|
||||
{flow_spec, rest}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp codec_src(%NxFlowSpecMatch{src: src_field}) when is_atom(src_field) do
|
||||
src_bin = Openflow.Match.codec_header(src_field)
|
||||
{@learn_src_field, src_bin}
|
||||
end
|
||||
defp codec_src(%NxFlowSpecMatch{src: src, dst: dst_field}) do
|
||||
src_bin = Openflow.Match.Field.codec(src, dst_field)
|
||||
{@learn_src_immediate, src_bin}
|
||||
end
|
||||
end
|
||||
38
lib/openflow/actions/nx_flow_spec_output.ex
Normal file
38
lib/openflow/actions/nx_flow_spec_output.ex
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
defmodule Openflow.Action.NxFlowSpecOutput do
|
||||
defstruct(
|
||||
n_bits: 0,
|
||||
src: nil,
|
||||
src_offset: 0
|
||||
)
|
||||
|
||||
@learn_src_field 0
|
||||
@learn_dst 2
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src = Keyword.get(options, :src)
|
||||
src_ofs = Keyword.get(options, :src_offset, 0)
|
||||
default_n_bits = Openflow.Match.Field.n_bits_of(src)
|
||||
n_bits = Keyword.get(options, :n_bits, default_n_bits)
|
||||
%NxFlowSpecOutput{n_bits: n_bits,
|
||||
src: src,
|
||||
src_offset: src_ofs}
|
||||
end
|
||||
|
||||
def to_binary(%NxFlowSpecOutput{n_bits: n_bits,
|
||||
src: src,
|
||||
src_offset: src_ofs}) do
|
||||
src_bin = Openflow.Match.codec_header(src)
|
||||
<<0::2, @learn_src_field::1, @learn_dst::2, n_bits::11, src_bin::4-bytes, src_ofs::16>>
|
||||
end
|
||||
|
||||
def read(<<0::2, @learn_src_field::1, @learn_dst::2,
|
||||
n_bits::11, src_bin::4-bytes, src_ofs::16, rest::bitstring>>) do
|
||||
src = Openflow.Match.codec_header(src_bin)
|
||||
flow_spec = %NxFlowSpecOutput{n_bits: n_bits,
|
||||
src: src,
|
||||
src_offset: src_ofs}
|
||||
{flow_spec, rest}
|
||||
end
|
||||
end
|
||||
78
lib/openflow/actions/nx_learn.ex
Normal file
78
lib/openflow/actions/nx_learn.ex
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
defmodule Openflow.Action.NxLearn do
|
||||
defstruct(
|
||||
idle_timeout: 0,
|
||||
hard_timeout: 0,
|
||||
priority: 0,
|
||||
cookie: 0,
|
||||
flags: [],
|
||||
table_id: 0,
|
||||
fin_idle_timeout: 0,
|
||||
fin_hard_timeout: 0,
|
||||
flow_specs: []
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 16
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
idle = Keyword.get(options, :idle_timeout, 0)
|
||||
hard = Keyword.get(options, :hard_timeout, 0)
|
||||
prio = Keyword.get(options, :priority, 0)
|
||||
cookie = Keyword.get(options, :cookie, 0)
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
table_id = Keyword.get(options, :table_id, 0)
|
||||
fin_idle = Keyword.get(options, :fin_idle_timeout, 0)
|
||||
fin_hard = Keyword.get(options, :fin_hard_timeout, 0)
|
||||
flow_specs = Keyword.get(options, :flow_specs, [])
|
||||
%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}
|
||||
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)
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bitstring>>) do
|
||||
<<idle::16, hard::16,
|
||||
prio::16, cookie::64, flags_int::16, table_id::8,
|
||||
_pad::size(1)-unit(8), fin_idle::16, fin_hard::16,
|
||||
flow_specs_bin::bitstring>> = body
|
||||
flags = Openflow.Enums.int_to_flags(flags_int, :nx_learn_flag)
|
||||
flow_specs = Openflow.Action.NxFlowSpec.read(flow_specs_bin)
|
||||
%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}
|
||||
end
|
||||
end
|
||||
106
lib/openflow/actions/nx_learn2.ex
Normal file
106
lib/openflow/actions/nx_learn2.ex
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
defmodule Openflow.Action.NxLearn2 do
|
||||
defstruct(
|
||||
idle_timeout: 0,
|
||||
hard_timeout: 0,
|
||||
priority: 0,
|
||||
cookie: 0,
|
||||
flags: [],
|
||||
table_id: 0,
|
||||
fin_idle_timeout: 0,
|
||||
fin_hard_timeout: 0,
|
||||
limit: 0,
|
||||
result_dst_offset: 0,
|
||||
result_dst: nil,
|
||||
flow_specs: []
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 45
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
idle = Keyword.get(options, :idle_timeout, 0)
|
||||
hard = Keyword.get(options, :hard_timeout, 0)
|
||||
prio = Keyword.get(options, :priority, 0)
|
||||
cookie = Keyword.get(options, :cookie, 0)
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
table_id = Keyword.get(options, :table_id, 0)
|
||||
fin_idle = Keyword.get(options, :fin_idle_timeout, 0)
|
||||
fin_hard = Keyword.get(options, :fin_hard_timeout, 0)
|
||||
flow_specs = Keyword.get(options, :flow_specs, [])
|
||||
limit = Keyword.get(options, :limit, 0)
|
||||
result_dst_offset = Keyword.get(options, :result_dst_offset, 0)
|
||||
result_dst = Keyword.get(options, :result_dst)
|
||||
%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_offset,
|
||||
result_dst: result_dst,
|
||||
flow_specs: flow_specs}
|
||||
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)
|
||||
result_dst_bin = if :write_result in flags do
|
||||
Openflow.Match.codec_header(result_dst)
|
||||
else
|
||||
""
|
||||
end
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<idle::16, hard::16, prio::16, cookie::64, flags_int::16, table_id::8,
|
||||
0::8, fin_idle::16, fin_hard::16, limit::32,
|
||||
result_dst_ofs::16, 0::size(2)-unit(8), rest::bytes>> = body
|
||||
flags = Openflow.Enums.int_to_flags(flags_int, :nx_learn_flag)
|
||||
learn = %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}
|
||||
if :write_result in flags do
|
||||
header_size = Openflow.Match.header_size(rest)
|
||||
<<result_dst_bin::size(header_size)-bytes, flow_specs_bin::bytes>> = rest
|
||||
result_dst = Openflow.Match.codec_header(result_dst_bin)
|
||||
flow_specs = Openflow.Action.NxFlowSpec.read(flow_specs_bin)
|
||||
struct(learn, %{result_dst: result_dst, flow_specs: flow_specs})
|
||||
else
|
||||
<<flow_specs_bin::bytes>> = rest
|
||||
flow_specs = Openflow.Action.NxFlowSpec.read(flow_specs_bin)
|
||||
struct(learn, %{flow_specs: flow_specs})
|
||||
end
|
||||
end
|
||||
end
|
||||
78
lib/openflow/actions/nx_multipath.ex
Normal file
78
lib/openflow/actions/nx_multipath.ex
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
defmodule Openflow.Action.NxMultipath do
|
||||
import Bitwise
|
||||
|
||||
defstruct(
|
||||
hash_field: :eth_src,
|
||||
basis: 0,
|
||||
algorithm: :modulo_n,
|
||||
max_link: 0,
|
||||
argument: 0,
|
||||
offset: 0,
|
||||
n_bits: 0,
|
||||
dst_field: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 10
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)
|
||||
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,
|
||||
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)
|
||||
body = <<hash_field_int::16, basis::16, 0::size(2)-unit(8),
|
||||
alg_int::16, max_link::16, arg::32, 0::size(2)-unit(8),
|
||||
ofs_nbits::16, dst_field_bin::4-bytes>>
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<hash_field_int::16, basis::16, _::size(2)-unit(8),
|
||||
alg_int::16, max_link::16, arg::32, _::size(2)-unit(8),
|
||||
ofs::10, n_bits::6, dst_field_bin::4-bytes>> = body
|
||||
hash_field = Openflow.Enums.to_atom(hash_field_int, :nx_hash_fields)
|
||||
alg = Openflow.Enums.to_atom(alg_int, :nx_mp_algorithm)
|
||||
dst_field = Openflow.Match.codec_header(dst_field_bin)
|
||||
%NxMultipath{hash_field: hash_field,
|
||||
basis: basis,
|
||||
algorithm: alg,
|
||||
max_link: max_link,
|
||||
argument: arg,
|
||||
offset: ofs,
|
||||
n_bits: n_bits + 1,
|
||||
dst_field: dst_field}
|
||||
end
|
||||
end
|
||||
121
lib/openflow/actions/nx_nat.ex
Normal file
121
lib/openflow/actions/nx_nat.ex
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
defmodule Openflow.Action.NxNat do
|
||||
defstruct(
|
||||
flags: [],
|
||||
ipv4_min: nil,
|
||||
ipv4_max: nil,
|
||||
ipv6_min: nil,
|
||||
ipv6_max: nil,
|
||||
proto_min: nil,
|
||||
proto_max: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 36
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)
|
||||
%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}
|
||||
end
|
||||
|
||||
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)
|
||||
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)>>
|
||||
end
|
||||
|
||||
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)
|
||||
range_flags = Openflow.Enums.int_to_flags(range_flags_int, :nx_nat_range)
|
||||
decode_ranges(%NxNat{flags: flags}, range_flags, ranges_bin)
|
||||
end
|
||||
|
||||
# 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)
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
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)
|
||||
rest ->
|
||||
decode_ranges(struct(nat, %{range => ""}), ranges, rest)
|
||||
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)
|
||||
rest ->
|
||||
decode_ranges(struct(nat, %{range => ""}), ranges, rest)
|
||||
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)
|
||||
rest ->
|
||||
decode_ranges(struct(nat, %{range => ""}), ranges, rest)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
26
lib/openflow/actions/nx_note.ex
Normal file
26
lib/openflow/actions/nx_note.ex
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
defmodule Openflow.Action.NxNote do
|
||||
defstruct(note: "")
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 8
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, note_bin::bytes>>) do
|
||||
note = Openflow.Utils.decode_string(note_bin)
|
||||
%NxNote{note: note}
|
||||
end
|
||||
end
|
||||
52
lib/openflow/actions/nx_output_reg.ex
Normal file
52
lib/openflow/actions/nx_output_reg.ex
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
defmodule Openflow.Action.NxOutputReg do
|
||||
import Bitwise
|
||||
|
||||
defstruct(
|
||||
n_bits: 0,
|
||||
offset: 0,
|
||||
src_field: nil,
|
||||
max_len: :no_buffer
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 15
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src_field = Keyword.get(options, :src_field)
|
||||
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}
|
||||
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 = <<ofs_nbits::16, src_field_bin::4-bytes, max_len::16, 0::size(6)-unit(8)>>
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<ofs::10, n_bits::6, src_field_bin::4-bytes, max_len::16, _::size(6)-unit(8)>> = body
|
||||
src_field = Openflow.Match.codec_header(src_field_bin)
|
||||
max_len = Openflow.Utils.get_enum(max_len, :controller_max_len)
|
||||
%NxOutputReg{n_bits: n_bits + 1,
|
||||
offset: ofs,
|
||||
src_field: src_field,
|
||||
max_len: max_len}
|
||||
end
|
||||
end
|
||||
51
lib/openflow/actions/nx_output_reg2.ex
Normal file
51
lib/openflow/actions/nx_output_reg2.ex
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
defmodule Openflow.Action.NxOutputReg2 do
|
||||
import Bitwise
|
||||
|
||||
defstruct(
|
||||
n_bits: 0,
|
||||
offset: 0,
|
||||
src_field: nil,
|
||||
max_len: :no_buffer
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 32
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src_field = Keyword.get(options, :src_field)
|
||||
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}
|
||||
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 = <<ofs_nbits::16, max_len::16, src_field_bin::bytes, 0::size(padding)-unit(8)>>
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<ofs::10, n_bits::6, max_len::16, oxm_header::4-bytes, rest::bitstring>> = body
|
||||
exp_size = match_header_size(oxm_header) - 4
|
||||
<<experimenter_int::size(exp_size)-unit(8), _padding::bytes>> = rest
|
||||
src_field = Openflow.Match.codec_header(<<oxm_header::bytes, experimenter_int::size(exp_size)-unit(8)>>)
|
||||
max_len = Openflow.Utils.get_enum(max_len, :controller_max_len)
|
||||
%NxOutputReg2{n_bits: n_bits + 1, offset: ofs, src_field: src_field, max_len: max_len}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp match_header_size(<<0xffff::16, _::bytes>>), do: 8
|
||||
defp match_header_size(<<_::16, _::bytes>>), do: 4
|
||||
end
|
||||
31
lib/openflow/actions/nx_output_trunc.ex
Normal file
31
lib/openflow/actions/nx_output_trunc.ex
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
defmodule Openflow.Action.NxOutputTrunc do
|
||||
defstruct(
|
||||
port_number: 0,
|
||||
max_len: :no_buffer
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 39
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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}
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, port_no_int::16, max_len::32>>) do
|
||||
port_no = Openflow.Utils.get_enum(port_no_int, :openflow10_port_no)
|
||||
%NxOutputTrunc{port_number: port_no, max_len: max_len}
|
||||
end
|
||||
end
|
||||
24
lib/openflow/actions/nx_pop_mpls.ex
Normal file
24
lib/openflow/actions/nx_pop_mpls.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Action.NxPopMpls do
|
||||
defstruct(ethertype: 0x8847)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 24
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(ethertype \\ 0x8847) 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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, ethertype::16, _::size(4)-unit(8)>>) do
|
||||
%NxPopMpls{ethertype: ethertype}
|
||||
end
|
||||
end
|
||||
24
lib/openflow/actions/nx_pop_queue.ex
Normal file
24
lib/openflow/actions/nx_pop_queue.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
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
|
||||
24
lib/openflow/actions/nx_push_mpls.ex
Normal file
24
lib/openflow/actions/nx_push_mpls.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Action.NxPushMpls do
|
||||
defstruct(ethertype: 0x8847)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 23
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(ethertype \\ 0x8847) 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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, ethertype::16, _::size(4)-unit(8)>>) do
|
||||
%NxPushMpls{ethertype: ethertype}
|
||||
end
|
||||
end
|
||||
54
lib/openflow/actions/nx_reg_load.ex
Normal file
54
lib/openflow/actions/nx_reg_load.ex
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
defmodule Openflow.Action.NxRegLoad do
|
||||
import Bitwise
|
||||
|
||||
defstruct(
|
||||
n_bits: 0,
|
||||
offset: 0,
|
||||
dst_field: nil,
|
||||
value: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 7
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
dst_field = Keyword.get(options, :dst_field)
|
||||
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}
|
||||
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 = <<tmp_value::64>>
|
||||
ofs_nbits = (ofs <<< 6) ||| (n_bits - 1)
|
||||
body = <<ofs_nbits::16, dst_field_bin::4-bytes, value_bin::bytes>>
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<ofs::10, n_bits::6, dst_field_bin::4-bytes, value_bin::bytes>> = body
|
||||
dst_field = Openflow.Match.codec_header(dst_field_bin)
|
||||
value = Openflow.Match.Field.codec(value_bin, dst_field)
|
||||
%NxRegLoad{n_bits: n_bits + 1,
|
||||
offset: ofs,
|
||||
dst_field: dst_field,
|
||||
value: value}
|
||||
end
|
||||
end
|
||||
40
lib/openflow/actions/nx_reg_load2.ex
Normal file
40
lib/openflow/actions/nx_reg_load2.ex
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
defmodule Openflow.Action.NxRegLoad2 do
|
||||
defstruct(
|
||||
dst_field: nil,
|
||||
value: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 33
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
dst_field = Keyword.get(options, :dst_field)
|
||||
value = Keyword.get(options, :value)
|
||||
%NxRegLoad2{dst_field: dst_field, value: value}
|
||||
end
|
||||
|
||||
def to_binary(%NxRegLoad2{dst_field: dst_field, value: value}) do
|
||||
match_bin =
|
||||
[{dst_field, value}]
|
||||
|> 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)
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, _::48, 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}
|
||||
end
|
||||
end
|
||||
56
lib/openflow/actions/nx_reg_move.ex
Normal file
56
lib/openflow/actions/nx_reg_move.ex
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
defmodule Openflow.Action.NxRegMove do
|
||||
defstruct(
|
||||
n_bits: 0,
|
||||
src_offset: 0,
|
||||
dst_offset: 0,
|
||||
src_field: nil,
|
||||
dst_field: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 6
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src_field = Keyword.get(options, :src_field)
|
||||
dst_field = Keyword.get(options, :dst_field)
|
||||
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,
|
||||
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)
|
||||
body = <<n_bits::16, src_ofs::16, dst_ofs::16,
|
||||
src_field_bin::4-bytes, dst_field_bin::4-bytes>>
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, body::bytes>>) do
|
||||
<<n_bits::16, src_ofs::16, dst_ofs::16,
|
||||
src_field_bin::4-bytes, dst_field_bin::4-bytes>> = body
|
||||
src_field = Openflow.Match.codec_header(src_field_bin)
|
||||
dst_field = Openflow.Match.codec_header(dst_field_bin)
|
||||
%NxRegMove{n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs,
|
||||
src_field: src_field,
|
||||
dst_field: dst_field}
|
||||
end
|
||||
end
|
||||
26
lib/openflow/actions/nx_resubmit.ex
Normal file
26
lib/openflow/actions/nx_resubmit.ex
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
defmodule Openflow.Action.NxResubmit do
|
||||
defstruct([in_port: :in_port])
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 1
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(in_port \\ :in_port) do
|
||||
%NxResubmit{in_port: in_port}
|
||||
end
|
||||
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, in_port_int::16, _::size(4)-unit(8)>>) do
|
||||
in_port = Openflow.Utils.get_enum(in_port_int, :openflow10_port_no)
|
||||
%NxResubmit{in_port: in_port}
|
||||
end
|
||||
end
|
||||
33
lib/openflow/actions/nx_resubmit_table.ex
Normal file
33
lib/openflow/actions/nx_resubmit_table.ex
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
defmodule Openflow.Action.NxResubmitTable do
|
||||
defstruct([in_port: :in_port, table_id: :all])
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 14
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)
|
||||
%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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, in_port_int::16, table_id_int::8, 0::size(3)-unit(8)>>) do
|
||||
in_port = Openflow.Utils.get_enum(in_port_int, :openflow10_port_no)
|
||||
table_id = Openflow.Utils.get_enum(table_id_int, :table_id)
|
||||
%NxResubmitTable{in_port: in_port, table_id: table_id}
|
||||
end
|
||||
end
|
||||
30
lib/openflow/actions/nx_resubmit_table_ct.ex
Normal file
30
lib/openflow/actions/nx_resubmit_table_ct.ex
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
defmodule Openflow.Action.NxResubmitTableCt do
|
||||
defstruct(in_port: :in_port, table_id: :all)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 44
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
in_port = Keyword.get(options, :in_port, :in_port)
|
||||
table_id = Keyword.get(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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, in_port_int::16, table_id_int::8, 0::size(3)-unit(8)>>) do
|
||||
in_port = Openflow.Utils.get_enum(in_port_int, :openflow10_port_no)
|
||||
table_id = Openflow.Utils.get_enum(table_id_int, :table_id)
|
||||
%NxResubmitTableCt{in_port: in_port, table_id: table_id}
|
||||
end
|
||||
end
|
||||
44
lib/openflow/actions/nx_sample.ex
Normal file
44
lib/openflow/actions/nx_sample.ex
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
defmodule Openflow.Action.NxSample do
|
||||
defstruct(
|
||||
probability: 0,
|
||||
collector_set_id: 0,
|
||||
obs_domain_id: 0,
|
||||
obs_point_id: 0
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 29
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)
|
||||
%NxSample{probability: probability,
|
||||
collector_set_id: collector_set_id,
|
||||
obs_domain_id: obs_domain_id,
|
||||
obs_point_id: obs_point_id}
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, probability::16,
|
||||
collector_set_id::32, obs_domain_id::32, obs_point_id::32>>) do
|
||||
%NxSample{probability: probability,
|
||||
collector_set_id: collector_set_id,
|
||||
obs_domain_id: obs_domain_id,
|
||||
obs_point_id: obs_point_id}
|
||||
end
|
||||
end
|
||||
49
lib/openflow/actions/nx_sample2.ex
Normal file
49
lib/openflow/actions/nx_sample2.ex
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
defmodule Openflow.Action.NxSample2 do
|
||||
defstruct(
|
||||
probability: 0,
|
||||
collector_set_id: 0,
|
||||
obs_domain_id: 0,
|
||||
obs_point_id: 0,
|
||||
sampling_port: 0
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 38
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)
|
||||
%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}
|
||||
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)>>
|
||||
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
|
||||
%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}
|
||||
end
|
||||
end
|
||||
56
lib/openflow/actions/nx_sample3.ex
Normal file
56
lib/openflow/actions/nx_sample3.ex
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
defmodule Openflow.Action.NxSample3 do
|
||||
defstruct(
|
||||
probability: 0,
|
||||
collector_set_id: 0,
|
||||
obs_domain_id: 0,
|
||||
obs_point_id: 0,
|
||||
sampling_port: 0,
|
||||
direction: :default
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 41
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)
|
||||
%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}
|
||||
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)
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@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)>>) do
|
||||
direction = Openflow.Enums.to_atom(direction_int, :nx_action_sample_direction)
|
||||
%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}
|
||||
end
|
||||
end
|
||||
24
lib/openflow/actions/nx_set_mpls_label.ex
Normal file
24
lib/openflow/actions/nx_set_mpls_label.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
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
|
||||
24
lib/openflow/actions/nx_set_mpls_tc.ex
Normal file
24
lib/openflow/actions/nx_set_mpls_tc.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
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
|
||||
24
lib/openflow/actions/nx_set_mpls_ttl.ex
Normal file
24
lib/openflow/actions/nx_set_mpls_ttl.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
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
|
||||
24
lib/openflow/actions/nx_set_queue.ex
Normal file
24
lib/openflow/actions/nx_set_queue.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
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
|
||||
24
lib/openflow/actions/nx_set_tunnel.ex
Normal file
24
lib/openflow/actions/nx_set_tunnel.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Action.NxSetTunnel do
|
||||
defstruct(tunnel_id: 0)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 2
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, _::16, tunnel_id::32>>) do
|
||||
%NxSetTunnel{tunnel_id: tunnel_id}
|
||||
end
|
||||
end
|
||||
24
lib/openflow/actions/nx_set_tunnel64.ex
Normal file
24
lib/openflow/actions/nx_set_tunnel64.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Action.NxSetTunnel64 do
|
||||
defstruct([tunnel_id: 0])
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 9
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, 0::size(6)-unit(8), tunnel_id::64>>) do
|
||||
%NxSetTunnel64{tunnel_id: tunnel_id}
|
||||
end
|
||||
end
|
||||
36
lib/openflow/actions/nx_stack_pop.ex
Normal file
36
lib/openflow/actions/nx_stack_pop.ex
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
defmodule Openflow.Action.NxStackPop do
|
||||
defstruct(
|
||||
n_bits: 0,
|
||||
offset: 0,
|
||||
field: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 28
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
field = Keyword.get(options, :field)
|
||||
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}
|
||||
end
|
||||
|
||||
def to_binary(%NxStackPop{n_bits: n_bits, offset: ofs, field: field}) do
|
||||
field_bin = Openflow.Match.codec_header(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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, ofs::16,
|
||||
field_bin::4-bytes, n_bits::16, _::size(6)-unit(8)>>) do
|
||||
field = Openflow.Match.codec_header(field_bin)
|
||||
%NxStackPop{n_bits: n_bits, offset: ofs, field: field}
|
||||
end
|
||||
end
|
||||
36
lib/openflow/actions/nx_stack_push.ex
Normal file
36
lib/openflow/actions/nx_stack_push.ex
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
defmodule Openflow.Action.NxStackPush do
|
||||
defstruct(
|
||||
n_bits: 0,
|
||||
offset: 0,
|
||||
field: nil
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 27
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
field = Keyword.get(options, :field)
|
||||
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}
|
||||
end
|
||||
|
||||
def to_binary(%NxStackPush{n_bits: n_bits, offset: ofs, field: field}) do
|
||||
field_bin = Openflow.Match.codec_header(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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, ofs::16,
|
||||
field_bin::4-bytes, n_bits::16, _::size(6)-unit(8)>>) do
|
||||
field = Openflow.Match.codec_header(field_bin)
|
||||
%NxStackPush{n_bits: n_bits, offset: ofs, field: field}
|
||||
end
|
||||
end
|
||||
32
lib/openflow/actions/nx_write_metadata.ex
Normal file
32
lib/openflow/actions/nx_write_metadata.ex
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
defmodule Openflow.Action.NxWriteMetadata do
|
||||
defstruct(
|
||||
metadata: 0,
|
||||
metadata_mask: 0xffffffffffffffff
|
||||
)
|
||||
|
||||
@experimenter 0x00002320
|
||||
@nxast 22
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
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)
|
||||
%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)>>
|
||||
end
|
||||
|
||||
def read(<<@experimenter::32, @nxast::16, _::size(6)-unit(8), metadata::64, metadata_mask::64>>) do
|
||||
%NxWriteMetadata{metadata: metadata, metadata_mask: metadata_mask}
|
||||
end
|
||||
end
|
||||
31
lib/openflow/actions/output.ex
Normal file
31
lib/openflow/actions/output.ex
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
defmodule Openflow.Action.Output do
|
||||
defstruct(
|
||||
port_number: 0,
|
||||
max_len: :no_buffer
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 0
|
||||
|
||||
def new(port) when not is_list(port) do
|
||||
new(port_number: port)
|
||||
end
|
||||
def new(options) when is_list(options) do
|
||||
port_no = Keyword.get(options, :port_number)
|
||||
max_len = Keyword.get(options, :max_len, :no_buffer)
|
||||
%Output{port_number: port_no, max_len: max_len}
|
||||
end
|
||||
|
||||
def to_binary(%Output{port_number: port_no, max_len: max_len}) do
|
||||
port_no_int = Openflow.Utils.get_enum(port_no, :openflow13_port_no)
|
||||
max_len = Openflow.Utils.get_enum(max_len, :controller_max_len)
|
||||
<<0::16, 16::16, port_no_int::32, max_len::16, 0::size(6)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<0::16, 16::16, port_no_int::32, max_len::16, _pad::size(6)-unit(8)>>) do
|
||||
port_no = Openflow.Utils.get_enum(port_no_int, :openflow13_port_no)
|
||||
max_len = Openflow.Utils.get_enum(max_len, :controller_max_len)
|
||||
%Output{port_number: port_no, max_len: max_len}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/pop_mpls.ex
Normal file
19
lib/openflow/actions/pop_mpls.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.PopMpls do
|
||||
defstruct(ethertype: 0x8847)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 20
|
||||
|
||||
def new(ethertype) do
|
||||
%PopMpls{ethertype: ethertype}
|
||||
end
|
||||
|
||||
def to_binary(%PopMpls{ethertype: ethertype}) do
|
||||
<<20::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<20::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>) do
|
||||
%PopMpls{ethertype: ethertype}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/pop_pbb.ex
Normal file
19
lib/openflow/actions/pop_pbb.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.PopPbb do
|
||||
defstruct([])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 27
|
||||
|
||||
def new do
|
||||
%PopPbb{}
|
||||
end
|
||||
|
||||
def to_binary(%PopPbb{}) do
|
||||
<<27::16, 8::16, 0::size(4)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<27::16, 8::16, _::size(4)-unit(8)>>) do
|
||||
%PopPbb{}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/pop_vlan.ex
Normal file
19
lib/openflow/actions/pop_vlan.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.PopVlan do
|
||||
defstruct([])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 18
|
||||
|
||||
def new do
|
||||
%PopVlan{}
|
||||
end
|
||||
|
||||
def to_binary(%PopVlan{}) do
|
||||
<<18::16, 8::16, 0::size(4)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<18::16, 8::16, _::size(4)-unit(8)>>) do
|
||||
%PopVlan{}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/push_mpls.ex
Normal file
19
lib/openflow/actions/push_mpls.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.PushMpls do
|
||||
defstruct(ethertype: 0x8847)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 19
|
||||
|
||||
def new(ethertype) do
|
||||
%PushMpls{ethertype: ethertype}
|
||||
end
|
||||
|
||||
def to_binary(%PushMpls{ethertype: ethertype}) do
|
||||
<<19::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<19::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>) do
|
||||
%PushMpls{ethertype: ethertype}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/push_pbb.ex
Normal file
19
lib/openflow/actions/push_pbb.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.PushPbb do
|
||||
defstruct(ethertype: 0x88e7)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 26
|
||||
|
||||
def new(ethertype) do
|
||||
%PushPbb{ethertype: ethertype}
|
||||
end
|
||||
|
||||
def to_binary(%PushPbb{ethertype: ethertype}) do
|
||||
<<26::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<26::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>) do
|
||||
%PushPbb{ethertype: ethertype}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/push_vlan.ex
Normal file
19
lib/openflow/actions/push_vlan.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.PushVlan do
|
||||
defstruct(ethertype: 0x8100)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 17
|
||||
|
||||
def new(ethertype) do
|
||||
%PushVlan{ethertype: ethertype}
|
||||
end
|
||||
|
||||
def to_binary(%PushVlan{ethertype: ethertype}) do
|
||||
<<17::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<17::16, 8::16, ethertype::16, 0::size(2)-unit(8)>>) do
|
||||
%PushVlan{ethertype: ethertype}
|
||||
end
|
||||
end
|
||||
34
lib/openflow/actions/set_field.ex
Normal file
34
lib/openflow/actions/set_field.ex
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
defmodule Openflow.Action.SetField do
|
||||
defstruct(field: nil)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
@set_field_size 8
|
||||
|
||||
def ofpat, do: 25
|
||||
|
||||
def new({_field, _value} = oxm_field) do
|
||||
%SetField{field: oxm_field}
|
||||
end
|
||||
|
||||
def to_binary(%SetField{field: {field, value}}) do
|
||||
match_bin =
|
||||
[{field, value}]
|
||||
|> Openflow.Match.new
|
||||
|> Openflow.Match.to_binary
|
||||
|
||||
<<1::16, _length::16, padded_field::bytes>> = match_bin
|
||||
patial_len = @set_field_size - 4 + byte_size(padded_field)
|
||||
padding = Openflow.Utils.padding(patial_len, 8)
|
||||
length = patial_len + padding
|
||||
<<25::16, length::16, padded_field::bytes, 0::size(padding)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<25::16, _length::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>>
|
||||
{[field|_], _rest} = Openflow.Match.read(match_bin)
|
||||
%SetField{field: field}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/set_mpls_ttl.ex
Normal file
19
lib/openflow/actions/set_mpls_ttl.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.SetMplsTtl do
|
||||
defstruct(ttl: 0)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 15
|
||||
|
||||
def new(ttl) do
|
||||
%SetMplsTtl{ttl: ttl}
|
||||
end
|
||||
|
||||
def to_binary(%SetMplsTtl{ttl: ttl}) do
|
||||
<<15::16, 8::16, ttl::8, 0::size(3)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<15::16, 8::16, ttl::8, _::size(3)-unit(8)>>) do
|
||||
%SetMplsTtl{ttl: ttl}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/set_nw_ttl.ex
Normal file
19
lib/openflow/actions/set_nw_ttl.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.SetNwTtl do
|
||||
defstruct(ttl: 0)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 23
|
||||
|
||||
def new(ttl) do
|
||||
%SetNwTtl{ttl: ttl}
|
||||
end
|
||||
|
||||
def to_binary(%SetNwTtl{ttl: ttl}) do
|
||||
<<23::16, 8::16, ttl::8, 0::size(3)-unit(8)>>
|
||||
end
|
||||
|
||||
def read(<<23::16, 8::16, ttl::8, _::size(3)-unit(8)>>) do
|
||||
%SetNwTtl{ttl: ttl}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/actions/set_queue.ex
Normal file
19
lib/openflow/actions/set_queue.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Action.SetQueue do
|
||||
defstruct(id: 0)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofpat, do: 21
|
||||
|
||||
def new(id) do
|
||||
%SetQueue{id: id}
|
||||
end
|
||||
|
||||
def to_binary(%SetQueue{id: id}) do
|
||||
<<21::16, 8::16, id::32>>
|
||||
end
|
||||
|
||||
def read(<<21::16, 8::16, id::32>>) do
|
||||
%SetQueue{id: id}
|
||||
end
|
||||
end
|
||||
24
lib/openflow/barrier/reply.ex
Normal file
24
lib/openflow/barrier/reply.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Barrier.Reply do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 21
|
||||
|
||||
def new do
|
||||
%Reply{}
|
||||
end
|
||||
|
||||
def read(_) do
|
||||
%Reply{}
|
||||
end
|
||||
|
||||
def to_binary(%Reply{}) do
|
||||
<<>>
|
||||
end
|
||||
end
|
||||
24
lib/openflow/barrier/request.ex
Normal file
24
lib/openflow/barrier/request.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Barrier.Request do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 20
|
||||
|
||||
def new do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def read(_) do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def to_binary(%Request{}) do
|
||||
<<>>
|
||||
end
|
||||
end
|
||||
54
lib/openflow/buckets.ex
Normal file
54
lib/openflow/buckets.ex
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
defmodule Openflow.Bucket do
|
||||
defstruct(
|
||||
weight: 0,
|
||||
watch_port: 0,
|
||||
watch_group: 0,
|
||||
actions: []
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
@header_size 16
|
||||
|
||||
def new(options) do
|
||||
weight = Keyword.get(options, :weight, 0)
|
||||
watch_port = Keyword.get(options, :watch_port, :any)
|
||||
watch_group = Keyword.get(options, :watch_group, :any)
|
||||
actions = Keyword.get(options, :actions, [])
|
||||
%Bucket{weight: weight, watch_port: watch_port, watch_group: watch_group, actions: actions}
|
||||
end
|
||||
|
||||
def read(buckets_bin) do
|
||||
do_read([], buckets_bin)
|
||||
end
|
||||
|
||||
def to_binary(buckets) do
|
||||
to_binary("", buckets)
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp do_read(acc, ""), do: Enum.reverse(acc)
|
||||
defp do_read(acc, <<length::16, weight::16, watch_port_int::32,
|
||||
watch_group_int::32, _::size(4)-unit(8), binary::bytes>>) do
|
||||
actions_len = length - @header_size
|
||||
<<actions_bin::size(actions_len)-bytes, rest::bytes>> = binary
|
||||
watch_port = Openflow.Utils.get_enum(watch_port_int, :openflow13_port_no)
|
||||
watch_group = Openflow.Utils.get_enum(watch_group_int, :group_id)
|
||||
actions = Openflow.Action.read(actions_bin)
|
||||
bucket = %Bucket{weight: weight, watch_port: watch_port, watch_group: watch_group, actions: actions}
|
||||
do_read([bucket|acc], rest)
|
||||
end
|
||||
|
||||
defp to_binary(acc, []), do: acc
|
||||
defp to_binary(acc, [bucket|rest]) do
|
||||
%Bucket{weight: weight, watch_port: watch_port, watch_group: watch_group, actions: actions} = bucket
|
||||
watch_port_int = Openflow.Utils.get_enum(watch_port, :openflow13_port_no)
|
||||
watch_group_int = Openflow.Utils.get_enum(watch_group, :group_id)
|
||||
actions_bin = Openflow.Action.to_binary(actions)
|
||||
length = byte_size(actions_bin) + @header_size
|
||||
bucket_bin = <<length::16, weight::16, watch_port_int::32,
|
||||
watch_group_int::32, 0::size(4)-unit(8), actions_bin::bytes>>
|
||||
to_binary(<<acc::bytes, bucket_bin::bytes>>, rest)
|
||||
end
|
||||
end
|
||||
2
lib/openflow/echo.ex
Normal file
2
lib/openflow/echo.ex
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
defmodule Openflow.Echo do
|
||||
end
|
||||
25
lib/openflow/echo/reply.ex
Normal file
25
lib/openflow/echo/reply.ex
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
defmodule Openflow.Echo.Reply do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
data: "",
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 3
|
||||
|
||||
def new(data \\ "") do
|
||||
%Reply{data: data}
|
||||
end
|
||||
|
||||
def read(data) do
|
||||
%Reply{data: data}
|
||||
end
|
||||
|
||||
def to_binary(%Reply{data: data}) do
|
||||
data
|
||||
end
|
||||
end
|
||||
26
lib/openflow/echo/request.ex
Normal file
26
lib/openflow/echo/request.ex
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
defmodule Openflow.Echo.Request do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
data: "",
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 2
|
||||
|
||||
def new(data \\ "") do
|
||||
%Request{data: data}
|
||||
end
|
||||
|
||||
def read(data) do
|
||||
%Request{data: data}
|
||||
end
|
||||
|
||||
def to_binary(%Request{data: data}) do
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
1081
lib/openflow/enums.ex
Normal file
1081
lib/openflow/enums.ex
Normal file
File diff suppressed because it is too large
Load diff
53
lib/openflow/error_msg.ex
Normal file
53
lib/openflow/error_msg.ex
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
defmodule Openflow.ErrorMsg do
|
||||
@moduledoc "OpenFlow Error codec module"
|
||||
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
type: nil,
|
||||
code: nil,
|
||||
data: "",
|
||||
exp_type: nil,
|
||||
experimenter: nil,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 1
|
||||
|
||||
def read(<<0xffff::16, exp_type::16, experimenter::32, data::bytes>>) do
|
||||
error_type = Openflow.Enums.to_atom(0xffff, :error_type)
|
||||
%ErrorMsg{
|
||||
type: error_type,
|
||||
exp_type: exp_type,
|
||||
experimenter: experimenter,
|
||||
data: data
|
||||
}
|
||||
end
|
||||
def read(<<type::16, code::16, data::bytes>>) do
|
||||
error_type = Openflow.Enums.to_atom(type, :error_type)
|
||||
error_code = Openflow.Enums.to_atom(code, error_type)
|
||||
%ErrorMsg{
|
||||
type: error_type,
|
||||
code: error_code,
|
||||
data: data
|
||||
}
|
||||
end
|
||||
|
||||
def to_binary(%ErrorMsg{type: :experimenter,
|
||||
exp_type: exp_type,
|
||||
experimenter: experimenter,
|
||||
data: data}) do
|
||||
error_type = Openflow.Enums.to_int(:experimenter, :error_type)
|
||||
<<error_type::16, exp_type::16, experimenter::32, data::bytes>>
|
||||
end
|
||||
def to_binary(%ErrorMsg{type: type,
|
||||
code: code,
|
||||
data: data}) do
|
||||
error_type = Openflow.Enums.to_int(type, :error_type)
|
||||
error_code = Openflow.Enums.to_int(code, type)
|
||||
<<error_type::16, error_code::16, data::bytes>>
|
||||
end
|
||||
end
|
||||
39
lib/openflow/experimenter.ex
Normal file
39
lib/openflow/experimenter.ex
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
defmodule Openflow.Experimenter do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: "",
|
||||
aux_id: 0,
|
||||
exp_id: 0,
|
||||
exp_type: 0,
|
||||
data: ""
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 4
|
||||
|
||||
def new(options) do
|
||||
%Experimenter{exp_id: Keyword.get(options, :exp_id, 0),
|
||||
exp_type: Keyword.get(options, :exp_type, 0),
|
||||
data: Keyword.get(options, :data, "")}
|
||||
end
|
||||
|
||||
def to_binary(%Experimenter{exp_id: exp_id, exp_type: exp_type, data: data}) do
|
||||
<<exp_id::32, exp_type::32, data::bytes>>
|
||||
end
|
||||
|
||||
def read(<<exp_id::32, exp_type::32, data::bytes>>) do
|
||||
case Openflow.Utils.get_enum(exp_id, :experimenter_id) do
|
||||
^exp_id ->
|
||||
%Experimenter{exp_id: exp_id, exp_type: exp_type, data: data}
|
||||
experimenter when is_atom(experimenter) ->
|
||||
case Openflow.Utils.get_enum(exp_type, experimenter) do
|
||||
^exp_type ->
|
||||
%Experimenter{exp_id: exp_id, exp_type: exp_type, data: data}
|
||||
codec when is_atom(codec) ->
|
||||
codec.read(<<exp_id::32, exp_type::32, data::bytes>>)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
2
lib/openflow/features.ex
Normal file
2
lib/openflow/features.ex
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
defmodule Openflow.Features do
|
||||
end
|
||||
39
lib/openflow/features/reply.ex
Normal file
39
lib/openflow/features/reply.ex
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
defmodule Openflow.Features.Reply do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: "",
|
||||
n_buffers: 0,
|
||||
n_tables: 0,
|
||||
aux_id: 0,
|
||||
capabilities: [],
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 6
|
||||
|
||||
def read(<<datapath_id::64-bits, n_buf::32, n_tab::8,
|
||||
aux_id::8, _pad::16, caps_int::32, _rsv::32>>) do
|
||||
dpid = Openflow.Utils.to_hex_string(datapath_id)
|
||||
flags = Openflow.Enums.int_to_flags(caps_int, :switch_capabilities)
|
||||
%Reply{
|
||||
datapath_id: dpid,
|
||||
n_buffers: n_buf,
|
||||
n_tables: n_tab,
|
||||
aux_id: aux_id,
|
||||
capabilities: flags
|
||||
}
|
||||
end
|
||||
|
||||
def to_binary(%Reply{
|
||||
datapath_id: datapath_id,
|
||||
n_buffers: n_buf,
|
||||
n_tables: n_tab,
|
||||
aux_id: aux_id,
|
||||
capabilities: flags}) do
|
||||
dpid_int = String.to_integer(datapath_id, 16)
|
||||
flags_int = Openflow.Enums.flags_to_int(flags, :switch_capabilities)
|
||||
<<dpid_int::64, n_buf::32, n_tab::8, aux_id::8, 0::16, flags_int::32, 0::32>>
|
||||
end
|
||||
end
|
||||
24
lib/openflow/features/request.ex
Normal file
24
lib/openflow/features/request.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Features.Request do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 5
|
||||
|
||||
def new do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def read(_) do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def to_binary(%Request{}) do
|
||||
<<>>
|
||||
end
|
||||
end
|
||||
109
lib/openflow/flow_mod.ex
Normal file
109
lib/openflow/flow_mod.ex
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
defmodule Openflow.FlowMod do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: "",
|
||||
aux_id: 0,
|
||||
cookie: 0,
|
||||
cookie_mask: 0,
|
||||
table_id: 0,
|
||||
command: :add,
|
||||
idle_timeout: 0,
|
||||
hard_timeout: 0,
|
||||
priority: 0,
|
||||
buffer_id: :no_buffer,
|
||||
out_port: :any,
|
||||
out_group: :any,
|
||||
flags: [],
|
||||
match: [],
|
||||
instructions: []
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 14
|
||||
|
||||
def new(options \\ []) do
|
||||
cookie = Keyword.get(options, :cookie, 0)
|
||||
cookie_mask = Keyword.get(options, :cookie_mask, 0)
|
||||
table_id = Keyword.get(options, :table_id, 0)
|
||||
command = Keyword.get(options, :command, :add)
|
||||
idle = Keyword.get(options, :idle_timeout, 0)
|
||||
hard = Keyword.get(options, :hard_timeout, 0)
|
||||
priority = Keyword.get(options, :priority, 0)
|
||||
buffer_id = Keyword.get(options, :buffer_id, :no_buffer)
|
||||
out_port = Keyword.get(options, :out_port, :any)
|
||||
out_group = Keyword.get(options, :out_group, :any)
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
match = Keyword.get(options, :match, Openflow.Match.new)
|
||||
instructions = Keyword.get(options, :instructions, [])
|
||||
%FlowMod{cookie: cookie,
|
||||
cookie_mask: cookie_mask,
|
||||
priority: priority,
|
||||
table_id: table_id,
|
||||
command: command,
|
||||
idle_timeout: idle,
|
||||
hard_timeout: hard,
|
||||
buffer_id: buffer_id,
|
||||
out_port: out_port,
|
||||
out_group: out_group,
|
||||
flags: flags,
|
||||
match: match,
|
||||
instructions: instructions}
|
||||
end
|
||||
|
||||
def read(<<cookie::64, cookie_mask::64, table_id_int::8, command_int::8,
|
||||
idle::16, hard::16, prio::16, buffer_id_int::32, out_port_int::32,
|
||||
out_group_int::32, flags_int::16, _::size(2)-unit(8), rest::bytes>>) do
|
||||
table_id = Openflow.Utils.get_enum(table_id_int, :table_id)
|
||||
command = Openflow.Utils.get_enum(command_int, :flow_mod_command)
|
||||
buffer_id = Openflow.Utils.get_enum(buffer_id_int, :buffer_id)
|
||||
out_port = Openflow.Utils.get_enum(out_port_int, :openflow13_port_no)
|
||||
out_group = Openflow.Utils.get_enum(out_group_int, :group_id)
|
||||
flags = Openflow.Enums.int_to_flags(flags_int, :flow_mod_flags)
|
||||
{match_fields, instructions_bin} = Openflow.Match.read(rest)
|
||||
match = Openflow.Match.new(match_fields)
|
||||
instructions = Openflow.Instruction.read(instructions_bin)
|
||||
%FlowMod{cookie: cookie,
|
||||
cookie_mask: cookie_mask,
|
||||
priority: prio,
|
||||
table_id: table_id,
|
||||
command: command,
|
||||
idle_timeout: idle,
|
||||
hard_timeout: hard,
|
||||
buffer_id: buffer_id,
|
||||
out_port: out_port,
|
||||
out_group: out_group,
|
||||
flags: flags,
|
||||
match: match,
|
||||
instructions: instructions}
|
||||
end
|
||||
|
||||
def to_binary(flow_mod) do
|
||||
%FlowMod{cookie: cookie,
|
||||
cookie_mask: cookie_mask,
|
||||
priority: prio,
|
||||
table_id: table_id,
|
||||
command: command,
|
||||
idle_timeout: idle,
|
||||
hard_timeout: hard,
|
||||
buffer_id: buffer_id,
|
||||
out_port: out_port,
|
||||
out_group: out_group,
|
||||
flags: flags,
|
||||
match: match_fields,
|
||||
instructions: instructions} = flow_mod
|
||||
table_id_int = Openflow.Utils.get_enum(table_id, :table_id)
|
||||
command_int = Openflow.Utils.get_enum(command, :flow_mod_command)
|
||||
buffer_id_int = Openflow.Utils.get_enum(buffer_id, :buffer_id)
|
||||
out_port_int = Openflow.Utils.get_enum(out_port, :openflow13_port_no)
|
||||
out_group_int = Openflow.Utils.get_enum(out_group, :group_id)
|
||||
flags_int = Openflow.Enums.flags_to_int(flags, :flow_mod_flags)
|
||||
match_fields_bin = Openflow.Match.to_binary(match_fields)
|
||||
instructions_bin = Openflow.Instruction.to_binary(instructions)
|
||||
<<cookie::64, cookie_mask::64, table_id_int::8, command_int::8,
|
||||
idle::16, hard::16, prio::16, buffer_id_int::32, out_port_int::32,
|
||||
out_group_int::32, flags_int::16, 0::size(2)-unit(8),
|
||||
match_fields_bin::bytes, instructions_bin::bytes>>
|
||||
end
|
||||
end
|
||||
42
lib/openflow/flow_removed.ex
Normal file
42
lib/openflow/flow_removed.ex
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
defmodule Openflow.FlowRemoved do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: "",
|
||||
aux_id: 0,
|
||||
cookie: 0,
|
||||
priority: 0,
|
||||
reason: :idle_timeout,
|
||||
table_id: 0,
|
||||
duration_sec: 0,
|
||||
duration_nsec: 0,
|
||||
idle_timeout: 0,
|
||||
hard_timeout: 0,
|
||||
packet_count: 0,
|
||||
byte_count: 0,
|
||||
match: []
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 11
|
||||
|
||||
def read(<<cookie::64, priority::16, reason_int::8,
|
||||
table_id_int::8, dsec::32, dnsec::32,
|
||||
idle::16, hard::16, pkt::64, byt::64, rest::bytes>>) do
|
||||
reason = Openflow.Enums.to_atom(reason_int, :flow_removed_reason)
|
||||
table_id = Openflow.Utils.get_enum(table_id_int, :table_id)
|
||||
{match_fields, _rest} = Openflow.Match.read(rest)
|
||||
%FlowRemoved{cookie: cookie,
|
||||
priority: priority,
|
||||
reason: reason,
|
||||
table_id: table_id,
|
||||
duration_sec: dsec,
|
||||
duration_nsec: dnsec,
|
||||
idle_timeout: idle,
|
||||
hard_timeout: hard,
|
||||
packet_count: pkt,
|
||||
byte_count: byt,
|
||||
match: match_fields}
|
||||
end
|
||||
end
|
||||
40
lib/openflow/get_async/reply.ex
Normal file
40
lib/openflow/get_async/reply.ex
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
defmodule Openflow.GetAsync.Reply do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0, # virtual field
|
||||
packet_in_mask_master: 0,
|
||||
packet_in_mask_slave: 0,
|
||||
port_status_mask_master: 0,
|
||||
port_status_mask_slave: 0,
|
||||
flow_removed_mask_master: 0,
|
||||
flow_removed_mask_slave: 0
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 27
|
||||
|
||||
def read(<<packet_in_mask_master::32, packet_in_mask_slave::32,
|
||||
port_status_mask_master::32, port_status_mask_slave::32,
|
||||
flow_removed_mask_master::32, flow_removed_mask_slave::32>>) do
|
||||
%Reply{packet_in_mask_master: packet_in_mask_master,
|
||||
packet_in_mask_slave: packet_in_mask_slave,
|
||||
port_status_mask_master: port_status_mask_master,
|
||||
port_status_mask_slave: port_status_mask_slave,
|
||||
flow_removed_mask_master: flow_removed_mask_master,
|
||||
flow_removed_mask_slave: flow_removed_mask_slave}
|
||||
end
|
||||
|
||||
def to_binary(%Reply{packet_in_mask_master: packet_in_mask_master,
|
||||
packet_in_mask_slave: packet_in_mask_slave,
|
||||
port_status_mask_master: port_status_mask_master,
|
||||
port_status_mask_slave: port_status_mask_slave,
|
||||
flow_removed_mask_master: flow_removed_mask_master,
|
||||
flow_removed_mask_slave: flow_removed_mask_slave}) do
|
||||
<<packet_in_mask_master::32, packet_in_mask_slave::32,
|
||||
port_status_mask_master::32, port_status_mask_slave::32,
|
||||
flow_removed_mask_master::32, flow_removed_mask_slave::32>>
|
||||
end
|
||||
end
|
||||
20
lib/openflow/get_async/request.ex
Normal file
20
lib/openflow/get_async/request.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
defmodule Openflow.GetAsync.Request do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 26
|
||||
|
||||
def read(_) do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def to_binary(%Request{}) do
|
||||
<<>>
|
||||
end
|
||||
end
|
||||
2
lib/openflow/get_config.ex
Normal file
2
lib/openflow/get_config.ex
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
defmodule Openflow.GetConfig do
|
||||
end
|
||||
26
lib/openflow/get_config/reply.ex
Normal file
26
lib/openflow/get_config/reply.ex
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
defmodule Openflow.GetConfig.Reply do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: "",
|
||||
aux_id: 0,
|
||||
flags: [], # default = "normal" is no special handling
|
||||
miss_send_len: 128
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 8
|
||||
|
||||
def read(<<flags_int::16, miss_send_len0::16>>) do
|
||||
flags = Openflow.Enums.int_to_flags(flags_int, :config_flags)
|
||||
miss_send_len = Openflow.Utils.get_enum(miss_send_len0, :controller_max_len)
|
||||
%Reply{flags: flags, miss_send_len: miss_send_len}
|
||||
end
|
||||
|
||||
def to_binary(%Reply{flags: flags, miss_send_len: miss_send_len0}) do
|
||||
flags_int = Openflow.Enums.flags_to_int(flags, :config_flags)
|
||||
miss_send_len = Openflow.Utils.get_enum(miss_send_len0, :controller_max_len)
|
||||
<<flags_int::16, miss_send_len::16>>
|
||||
end
|
||||
end
|
||||
24
lib/openflow/get_config/request.ex
Normal file
24
lib/openflow/get_config/request.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.GetConfig.Request do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: 0 # virtual field
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 7
|
||||
|
||||
def new do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def read(_) do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def to_binary(%Request{}) do
|
||||
<<>>
|
||||
end
|
||||
end
|
||||
49
lib/openflow/group_mod.ex
Normal file
49
lib/openflow/group_mod.ex
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
defmodule Openflow.GroupMod do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: "",
|
||||
aux_id: 0,
|
||||
command: :add,
|
||||
type: :all,
|
||||
group_id: 0,
|
||||
buckets: []
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 15
|
||||
|
||||
def new(options \\ []) do
|
||||
command = Keyword.get(options, :command, :add)
|
||||
type = Keyword.get(options, :type, :all)
|
||||
group_id = Keyword.get(options, :group_id, 0)
|
||||
buckets = Keyword.get(options, :buckets, [])
|
||||
%GroupMod{command: command,
|
||||
type: type,
|
||||
group_id: group_id,
|
||||
buckets: buckets}
|
||||
end
|
||||
|
||||
def read(<<command_int::16, type_int::8, _::8, group_id_int::32, buckets_bin::bytes>>) do
|
||||
command = Openflow.Utils.get_enum(command_int, :group_mod_command)
|
||||
type = Openflow.Utils.get_enum(type_int, :group_type)
|
||||
group_id = Openflow.Utils.get_enum(group_id_int, :group_id)
|
||||
buckets = Openflow.Bucket.read(buckets_bin)
|
||||
%GroupMod{command: command,
|
||||
type: type,
|
||||
group_id: group_id,
|
||||
buckets: buckets}
|
||||
end
|
||||
|
||||
def to_binary(%GroupMod{command: command,
|
||||
type: type,
|
||||
group_id: group_id,
|
||||
buckets: buckets}) do
|
||||
command_int = Openflow.Utils.get_enum(command, :group_mod_command)
|
||||
type_int = Openflow.Utils.get_enum(type, :group_type)
|
||||
group_id_int = Openflow.Utils.get_enum(group_id, :group_id)
|
||||
buckets_bin = Openflow.Bucket.to_binary(buckets)
|
||||
<<command_int::16, type_int::8, 0::8, group_id_int::32, buckets_bin::bytes>>
|
||||
end
|
||||
end
|
||||
103
lib/openflow/hello.ex
Normal file
103
lib/openflow/hello.ex
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
defmodule Openflow.Hello do
|
||||
@moduledoc "OpenFlow Hello codec module"
|
||||
|
||||
import Bitwise
|
||||
|
||||
@ofp_hello_size 4
|
||||
|
||||
defstruct(version: 4, xid: 0, elements: [])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type,
|
||||
do: 0
|
||||
|
||||
def new(version) when is_integer(version) do
|
||||
%Hello{elements: [versionbitmap: [version]]}
|
||||
end
|
||||
def new(versions) when is_list(versions) do
|
||||
%Hello{elements: [versionbitmap: versions]}
|
||||
end
|
||||
|
||||
def supported_version?(%Hello{version: 4, elements: []}), do: true
|
||||
def supported_version?(%Hello{elements: []}), do: false
|
||||
def supported_version?(%Hello{elements: elements}) do
|
||||
versionbitmaps = for {:versionbitmap, versions} <- elements, do: versions
|
||||
Enum.any?(versionbitmaps, fn(versions) -> 4 in versions end)
|
||||
end
|
||||
|
||||
def read(binary),
|
||||
do: %Hello{elements: decode([], binary)}
|
||||
|
||||
def to_binary(%Hello{elements: elements}),
|
||||
do: encode([], elements)
|
||||
|
||||
# private functions
|
||||
|
||||
defp decode(acc, <<>>), do: acc
|
||||
defp decode(acc, <<typeint::16, length::16, rest::bytes>>) do
|
||||
data_len = length - @ofp_hello_size
|
||||
<<data::bytes-size(data_len), rest2::bytes>> = rest
|
||||
|
||||
try do
|
||||
typeint
|
||||
|> Openflow.Enums.to_atom(:hello_elem)
|
||||
|> decode_hello_elem(acc, data)
|
||||
|> decode(rest2)
|
||||
catch
|
||||
:bad_enum ->
|
||||
decode(acc, rest2)
|
||||
end
|
||||
end
|
||||
|
||||
defp encode(acc, []),
|
||||
do: to_string(acc)
|
||||
defp encode(acc, [h|rest]),
|
||||
do: encode([encode_hello_elem(h)|acc], rest)
|
||||
|
||||
defp decode_hello_elem(:versionbitmap, acc, binary),
|
||||
do: [{:versionbitmap, decode_bitmap([], binary, 0)}|acc]
|
||||
defp decode_hello_elem(_, acc, _binary),
|
||||
do: acc
|
||||
|
||||
defp encode_hello_elem({:versionbitmap, versions}) do
|
||||
bitmap_bin = encode_bitmap(versions)
|
||||
type_int = Openflow.Enums.to_int(:versionbitmap, :hello_elem)
|
||||
size_int = @ofp_hello_size + byte_size(bitmap_bin)
|
||||
<<type_int::16, size_int::16, bitmap_bin::bytes>>
|
||||
end
|
||||
defp encode_hello_elem(_) do
|
||||
<<>>
|
||||
end
|
||||
|
||||
defp decode_bitmap(acc, "", _), do: acc
|
||||
defp decode_bitmap(acc, <<int::32, rest::bytes>>, base) do
|
||||
acc
|
||||
|> decode_bitmap(int, 0, base)
|
||||
|> decode_bitmap(rest, base + 32)
|
||||
end
|
||||
|
||||
defp encode_bitmap(list) do
|
||||
size =
|
||||
list
|
||||
|> Enum.max
|
||||
|> div(32)
|
||||
encode_bitmap(0, list, size)
|
||||
end
|
||||
|
||||
defp decode_bitmap(acc, _, index, _) when index >= 32,
|
||||
do: acc
|
||||
defp decode_bitmap(acc, int, index, base) when (int &&& (1 <<< index)) == 0,
|
||||
do: decode_bitmap(acc, int, index + 1, base)
|
||||
defp decode_bitmap(acc, int, index, base),
|
||||
do: decode_bitmap([base + index|acc], int, index + 1, base)
|
||||
|
||||
defp encode_bitmap(acc, [], size) do
|
||||
bytes = (size + 1) * 32
|
||||
<<acc::size(bytes)>>
|
||||
end
|
||||
defp encode_bitmap(acc, [h|rest], size) do
|
||||
index = (size - div(h, 32) * 32 + rem(h, 32))
|
||||
encode_bitmap(acc ||| (1 <<< index), rest, size)
|
||||
end
|
||||
end
|
||||
28
lib/openflow/instruction.ex
Normal file
28
lib/openflow/instruction.ex
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
defmodule Openflow.Instruction do
|
||||
|
||||
def read(instruction_bin) do
|
||||
do_read([], instruction_bin)
|
||||
end
|
||||
|
||||
def to_binary(instructions) when is_list(instructions) do
|
||||
to_binary(<<>>, instructions)
|
||||
end
|
||||
def to_binary(instruction) do
|
||||
to_binary([instruction])
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp do_read(acc, <<>>), do: Enum.reverse(acc)
|
||||
defp do_read(acc, <<type::16, length::16, _::bytes>> = binary) do
|
||||
<<instruction_bin::size(length)-bytes, rest::bytes>> = binary
|
||||
codec = Openflow.Enums.to_atom(type, :instruction_type)
|
||||
do_read([codec.read(instruction_bin)|acc], rest)
|
||||
end
|
||||
|
||||
defp to_binary(acc, []), do: acc
|
||||
defp to_binary(acc, [instruction|rest]) do
|
||||
codec = instruction.__struct__
|
||||
to_binary(<<acc::bytes, (codec.to_binary(instruction))::bytes>>, rest)
|
||||
end
|
||||
end
|
||||
20
lib/openflow/instructions/apply_actions.ex
Normal file
20
lib/openflow/instructions/apply_actions.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
defmodule Openflow.Instruction.ApplyActions do
|
||||
defstruct(actions: [])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(actions) do
|
||||
%ApplyActions{actions: actions}
|
||||
end
|
||||
|
||||
def to_binary(%ApplyActions{actions: actions}) do
|
||||
actions_bin = Openflow.Action.to_binary(actions)
|
||||
length = 8 + byte_size(actions_bin)
|
||||
<<4::16, length::16, 0::size(4)-unit(8), actions_bin::bytes>>
|
||||
end
|
||||
|
||||
def read(<<4::16, _length::16, _::size(4)-unit(8), actions_bin::bytes>>) do
|
||||
actions = Openflow.Action.read(actions_bin)
|
||||
%ApplyActions{actions: actions}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/instructions/clear_actions.ex
Normal file
19
lib/openflow/instructions/clear_actions.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Instruction.ClearActions do
|
||||
defstruct([])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new do
|
||||
%ClearActions{}
|
||||
end
|
||||
|
||||
def to_binary(%ClearActions{}) do
|
||||
actions_bin = ""
|
||||
length = 8 + byte_size(actions_bin)
|
||||
<<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
|
||||
%ClearActions{}
|
||||
end
|
||||
end
|
||||
18
lib/openflow/instructions/experimenter.ex
Normal file
18
lib/openflow/instructions/experimenter.ex
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
defmodule Openflow.Instruction.Experimenter do
|
||||
defstruct(exp_id: 0, data: "")
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(exp_id, data) do
|
||||
%Experimenter{exp_id: exp_id, data: data}
|
||||
end
|
||||
|
||||
def to_binary(%Experimenter{exp_id: exp_id, data: data}) do
|
||||
length = 8 + byte_size(data)
|
||||
<<0xffff::16, length::16, exp_id::32, data::bytes>>
|
||||
end
|
||||
|
||||
def read(<<0xffff::16, _::16, exp_id::32, data::bytes>>) do
|
||||
%Experimenter{exp_id: exp_id, data: data}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/instructions/goto_table.ex
Normal file
19
lib/openflow/instructions/goto_table.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Instruction.GotoTable do
|
||||
defstruct(table_id: 0)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(table_id) do
|
||||
%GotoTable{table_id: table_id}
|
||||
end
|
||||
|
||||
def to_binary(%GotoTable{table_id: table_id}) do
|
||||
table_id_int = Openflow.Utils.get_enum(table_id, :table_id)
|
||||
<<1::16, 8::16, table_id_int::8, 0::size(3)-unit(8)>>
|
||||
end
|
||||
|
||||
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)
|
||||
%GotoTable{table_id: table_id}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/instructions/meter.ex
Normal file
19
lib/openflow/instructions/meter.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Instruction.Meter do
|
||||
defstruct(meter_id: 0)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(meter_id) do
|
||||
%Meter{meter_id: meter_id}
|
||||
end
|
||||
|
||||
def to_binary(%Meter{meter_id: meter_id}) do
|
||||
meter_id_int = Openflow.Utils.get_enum(meter_id, :meter_id)
|
||||
<<6::16, 8::16, meter_id_int::32>>
|
||||
end
|
||||
|
||||
def read(<<6::16, _::16, meter_id_int::32>>) do
|
||||
meter_id = Openflow.Utils.get_enum(meter_id_int, :meter_id)
|
||||
%Meter{meter_id: meter_id}
|
||||
end
|
||||
end
|
||||
20
lib/openflow/instructions/write_actions.ex
Normal file
20
lib/openflow/instructions/write_actions.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
defmodule Openflow.Instruction.WriteActions do
|
||||
defstruct(actions: [])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(actions) do
|
||||
%WriteActions{actions: actions}
|
||||
end
|
||||
|
||||
def to_binary(%WriteActions{actions: actions}) do
|
||||
actions_bin = Openflow.Action.to_binary(actions)
|
||||
length = 8 + byte_size(actions_bin)
|
||||
<<3::16, length::16, 0::size(4)-unit(8), actions_bin::bytes>>
|
||||
end
|
||||
|
||||
def read(<<3::16, _length::16, _::size(4)-unit(8), actions_bin::bytes>>) do
|
||||
actions = Openflow.Action.read(actions_bin)
|
||||
%WriteActions{actions: actions}
|
||||
end
|
||||
end
|
||||
19
lib/openflow/instructions/write_metadata.ex
Normal file
19
lib/openflow/instructions/write_metadata.ex
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Openflow.Instruction.WriteMetadata do
|
||||
defstruct(metadata: 0, metadata_mask: 0xffffffffffffffff)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
metadata = Keyword.get(options, :metadata, 0)
|
||||
metadata_mask = Keyword.get(options, :metadata_mask, 0xffffffffffffffff)
|
||||
%WriteMetadata{metadata: metadata, metadata_mask: metadata_mask}
|
||||
end
|
||||
|
||||
def to_binary(%WriteMetadata{metadata: metadata, metadata_mask: metadata_mask}) do
|
||||
<<2::16, 24::16, 0::size(4)-unit(8), metadata::64, metadata_mask::64>>
|
||||
end
|
||||
|
||||
def read(<<2::16, 24::16, _::size(4)-unit(8), metadata::64, metadata_mask::64>>) do
|
||||
%WriteMetadata{metadata: metadata, metadata_mask: metadata_mask}
|
||||
end
|
||||
end
|
||||
154
lib/openflow/match.ex
Normal file
154
lib/openflow/match.ex
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
defmodule Openflow.Match do
|
||||
@match_size 8
|
||||
@header_size 4
|
||||
|
||||
defstruct([
|
||||
type: :oxm,
|
||||
fields: []
|
||||
])
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def new(fields \\ []) do
|
||||
oxm_fields =
|
||||
fields
|
||||
|> keyword_to_oxm_fields([])
|
||||
%Match{type: :oxm, fields: oxm_fields}
|
||||
end
|
||||
|
||||
def read(binary) do
|
||||
<<1::16, no_pad_len::16, binary1::binary>> = binary
|
||||
padding_length = @match_size - rem(no_pad_len, 8)
|
||||
match_field_len = no_pad_len - @header_size
|
||||
<<match_fields::size(match_field_len)-binary, _::size(padding_length)-unit(8), rest::bitstring>> = binary1
|
||||
{decode_fields(match_fields, []), rest}
|
||||
end
|
||||
|
||||
def to_binary(%Match{fields: fields}) do
|
||||
fields_bin = encode_fields(fields, <<>>)
|
||||
length = byte_size(fields_bin) + @match_size - @header_size
|
||||
type_int = Openflow.Enums.to_int(:oxm, :match_type)
|
||||
padding = Openflow.Utils.padding(length, 8)
|
||||
<<type_int::16, length::16, fields_bin::bytes, 0::size(padding)-unit(8)>>
|
||||
end
|
||||
|
||||
def codec_header(oxm_field) when is_atom(oxm_field) do
|
||||
case Openflow.Match.Field.vendor_of(oxm_field) do
|
||||
oxm_class when oxm_class in [:nxm_0, :nxm_1, :openflow_basic, :packet_register] ->
|
||||
oxm_class_int = Openflow.Enums.to_int(oxm_class, :oxm_class)
|
||||
oxm_field_int = Openflow.Enums.to_int(oxm_field, oxm_class)
|
||||
oxm_length = div(Openflow.Match.Field.n_bits_of(oxm_field), 8)
|
||||
<<oxm_class_int::16, oxm_field_int::7, 0::1, oxm_length::8>>
|
||||
experimenter when experimenter in [:nicira_ext_match, :onf_ext_match] ->
|
||||
oxm_class_int = 0xffff
|
||||
experimenter_int = Openflow.Enums.to_int(experimenter, :experimenter_oxm_vendors)
|
||||
oxm_field_int = Openflow.Enums.to_int(oxm_field, experimenter)
|
||||
oxm_length = div(Openflow.Match.Field.n_bits_of(oxm_field) + 4, 8)
|
||||
<<oxm_class_int::16, oxm_field_int::7, 0::1, oxm_length::8, experimenter_int::32>>
|
||||
end
|
||||
end
|
||||
def codec_header(<<oxm_class_int::16, oxm_field_int::7, _oxm_has_mask::1, _oxm_length::8>>) do
|
||||
oxm_class = Openflow.Enums.to_atom(oxm_class_int, :oxm_class)
|
||||
Openflow.Enums.to_atom(oxm_field_int, oxm_class)
|
||||
end
|
||||
def codec_header(<<0xffff::16, oxm_field_int::7, _oxm_has_mask::1, _oxm_length::8, experimenter_int::32>>) do
|
||||
experimenter = Openflow.Enums.to_atom(experimenter_int, :experimenter_oxm_vendors)
|
||||
Openflow.Enums.to_atom(oxm_field_int, experimenter)
|
||||
end
|
||||
|
||||
def header_size(<<_oxm_class_int::16, _oxm_field_int::7, _oxm_has_mask::1, _oxm_length::8, _::bytes>>),
|
||||
do: 4
|
||||
def header_size(<<0xffff::16, _oxm_field_int::7, _oxm_has_mask::1, _oxm_length::8, _exp_int::32, _::bytes>>),
|
||||
do: 8
|
||||
|
||||
# private functions
|
||||
|
||||
defp decode_fields(<<>>, acc), do: Enum.reverse(acc)
|
||||
defp decode_fields(<<0xffff::16, _::7, 1::1, length::8, vendor_int::32, field_int::16, binary::bytes>>, acc) do
|
||||
length = length - 6
|
||||
field_len = div(length, 2)
|
||||
<<value_bin::size(field_len)-bytes, mask_bin::size(field_len)-bytes, rest::bytes>> = binary
|
||||
experimenter = Openflow.Enums.to_atom(vendor_int, :experimenter_oxm_vendors)
|
||||
field_name = Openflow.Enums.to_atom(field_int, experimenter)
|
||||
value = Openflow.Match.Field.codec(value_bin, field_name)
|
||||
mask = Openflow.Match.Field.codec(mask_bin, field_name)
|
||||
decode_fields(rest, [{field_name, {value, mask}}|acc])
|
||||
end
|
||||
defp decode_fields(<<0xffff::16, _::7, 0::1, length::8, vendor_int::32, field_int::16, binary::bytes>>, acc) do
|
||||
length = length - 6
|
||||
<<value_bin::size(length)-bytes, rest::bytes>> = binary
|
||||
experimenter = Openflow.Enums.to_atom(vendor_int, :experimenter_oxm_vendors)
|
||||
field_name = Openflow.Enums.to_atom(field_int, experimenter)
|
||||
value = Openflow.Match.Field.codec(value_bin, field_name)
|
||||
decode_fields(rest, [{field_name, value}|acc])
|
||||
end
|
||||
defp decode_fields(<<class_int::16, field_int::7, 1::1, length::8, binary::bytes>>, acc) do
|
||||
field_len = div(length, 2)
|
||||
<<value_bin::size(field_len)-bytes, mask_bin::size(field_len)-bytes, rest::bytes>> = binary
|
||||
class = Openflow.Enums.to_atom(class_int, :oxm_class)
|
||||
field_name = Openflow.Enums.to_atom(field_int, class)
|
||||
value = Openflow.Match.Field.codec(value_bin, field_name)
|
||||
mask = Openflow.Match.Field.codec(mask_bin, field_name)
|
||||
decode_fields(rest, [{field_name, {value, mask}}|acc])
|
||||
end
|
||||
defp decode_fields(<<class_int::16, field_int::7, 0::1, length::8, binary::bytes>>, acc) do
|
||||
<<value_bin::size(length)-bytes, rest::bytes>> = binary
|
||||
class = Openflow.Enums.to_atom(class_int, :oxm_class)
|
||||
field_name = Openflow.Enums.to_atom(field_int, class)
|
||||
value = Openflow.Match.Field.codec(value_bin, field_name)
|
||||
decode_fields(rest, [{field_name, value}|acc])
|
||||
end
|
||||
|
||||
defp encode_fields([], acc), do: acc
|
||||
defp encode_fields([field|fields], acc) do
|
||||
encode_fields(fields, <<acc::bytes, (encode_field(field))::bytes>>)
|
||||
end
|
||||
|
||||
defp encode_field(%{class: class, field: field, has_mask: true, value: value, mask: mask})
|
||||
when class == :nicira_ext_match or class == :onf_ext_match do
|
||||
vendor_int = Openflow.Enums.to_int(class, :experimenter_oxm_vendors)
|
||||
field_int = Openflow.Enums.to_int(field, class)
|
||||
has_mask_int = 1
|
||||
length = (byte_size(value) * 2) + 6
|
||||
<<0xffff::16, 0::7, has_mask_int::1, length::8, vendor_int::32, field_int::16, value::bytes, mask::bytes>>
|
||||
end
|
||||
defp encode_field(%{class: class, field: field, has_mask: false, value: value})
|
||||
when class == :nicira_ext_match or class == :onf_ext_match do
|
||||
vendor_int = Openflow.Enums.to_int(class, :experimenter_oxm_vendors)
|
||||
field_int = Openflow.Enums.to_int(field, class)
|
||||
has_mask_int = 0
|
||||
length = byte_size(value) + 6
|
||||
<<0xffff::16, 0::7, has_mask_int::1, length::8, vendor_int::32, field_int::16, value::bytes>>
|
||||
end
|
||||
defp encode_field(%{class: class, field: field, has_mask: true, value: value, mask: mask}) do
|
||||
class_int = Openflow.Enums.to_int(class, :oxm_class)
|
||||
field_int = Openflow.Enums.to_int(field, class)
|
||||
has_mask_int = 1
|
||||
length = byte_size(value) * 2
|
||||
<<class_int::16, field_int::7, has_mask_int::1, length::8, value::bytes, mask::bytes>>
|
||||
end
|
||||
defp encode_field(%{class: class, field: field, has_mask: false, value: value}) do
|
||||
class_int = Openflow.Enums.to_int(class, :oxm_class)
|
||||
field_int = Openflow.Enums.to_int(field, class)
|
||||
has_mask_int = 0
|
||||
length = byte_size(value)
|
||||
<<class_int::16, field_int::7, has_mask_int::1, length::8, value::bytes>>
|
||||
end
|
||||
|
||||
defp keyword_to_oxm_fields([], acc), do: Enum.reverse(acc)
|
||||
defp keyword_to_oxm_fields([{field_name, field_value}|fields], acc) do
|
||||
keyword_to_oxm_fields(fields, [oxm_field(field_name, field_value)|acc])
|
||||
end
|
||||
|
||||
defp oxm_field(field_name, {value, mask}) do
|
||||
value_bin = Openflow.Match.Field.codec(value, field_name)
|
||||
mask_bin = Openflow.Match.Field.codec(mask, field_name)
|
||||
match_class = Openflow.Match.Field.vendor_of(field_name)
|
||||
%{class: match_class, field: field_name, has_mask: true, value: value_bin, mask: mask_bin}
|
||||
end
|
||||
defp oxm_field(field_name, value) do
|
||||
value_bin = Openflow.Match.Field.codec(value, field_name)
|
||||
match_class = Openflow.Match.Field.vendor_of(field_name)
|
||||
%{class: match_class, field: field_name, has_mask: false, value: value_bin}
|
||||
end
|
||||
end
|
||||
636
lib/openflow/match/field.ex
Normal file
636
lib/openflow/match/field.ex
Normal file
|
|
@ -0,0 +1,636 @@
|
|||
defmodule Openflow.Match.Field do
|
||||
|
||||
def codec(value0, field) when is_binary(value0) do
|
||||
{type, format} = format_of(field)
|
||||
n_bits = n_bits_of(field)
|
||||
bit_size = bit_size(value0)
|
||||
value = if bit_size < n_bits do
|
||||
head_pad_len = n_bits - bit_size
|
||||
<<0::size(head_pad_len), value0::bytes>>
|
||||
else
|
||||
if bit_size > n_bits and type != :mac do
|
||||
head_pad_len = bit_size - n_bits
|
||||
<<_::size(head_pad_len), value::size(n_bits)-bits>> = value0
|
||||
value
|
||||
else
|
||||
value0
|
||||
end
|
||||
end
|
||||
formatting(value, type, format)
|
||||
end
|
||||
def codec(value, type) do
|
||||
{type, format} = format_of(type)
|
||||
formatting(value, type, format)
|
||||
end
|
||||
|
||||
def n_bits_of(field) do
|
||||
field
|
||||
|> format_of
|
||||
|> bit_size_of
|
||||
end
|
||||
|
||||
def bit_size_of({:u8, _}), do: 8
|
||||
def bit_size_of({:u24, _}), do: 24
|
||||
def bit_size_of({:be16, _}), do: 16
|
||||
def bit_size_of({:be32, _}), do: 32
|
||||
def bit_size_of({:be64, _}), do: 64
|
||||
def bit_size_of({:be128, _}), do: 128
|
||||
def bit_size_of({:mac, _}), do: 48
|
||||
|
||||
# NXM0
|
||||
def vendor_of(:nx_in_port), do: :nxm_0
|
||||
def vendor_of(:nx_eth_dst), do: :nxm_0
|
||||
def vendor_of(:nx_eth_src), do: :nxm_0
|
||||
def vendor_of(:nx_eth_type), do: :nxm_0
|
||||
def vendor_of(:nx_vlan_tci), do: :nxm_0
|
||||
def vendor_of(:nx_ip_tos), do: :nxm_0
|
||||
def vendor_of(:nx_ip_proto), do: :nxm_0
|
||||
def vendor_of(:nx_ipv4_src), do: :nxm_0
|
||||
def vendor_of(:nx_ipv4_dst), do: :nxm_0
|
||||
def vendor_of(:nx_tcp_src), do: :nxm_0
|
||||
def vendor_of(:nx_tcp_dst), do: :nxm_0
|
||||
def vendor_of(:nx_udp_src), do: :nxm_0
|
||||
def vendor_of(:nx_udp_dst), do: :nxm_0
|
||||
def vendor_of(:nx_icmpv4_type), do: :nxm_0
|
||||
def vendor_of(:nx_icmpv4_code), do: :nxm_0
|
||||
def vendor_of(:nx_arp_op), do: :nxm_0
|
||||
def vendor_of(:nx_arp_spa), do: :nxm_0
|
||||
def vendor_of(:nx_arp_tpa), do: :nxm_0
|
||||
def vendor_of(:nx_tcp_flags), do: :nxm_0
|
||||
|
||||
# NXM1
|
||||
def vendor_of(:reg0), do: :nxm_1
|
||||
def vendor_of(:reg1), do: :nxm_1
|
||||
def vendor_of(:reg2), do: :nxm_1
|
||||
def vendor_of(:reg3), do: :nxm_1
|
||||
def vendor_of(:reg4), do: :nxm_1
|
||||
def vendor_of(:reg5), do: :nxm_1
|
||||
def vendor_of(:reg6), do: :nxm_1
|
||||
def vendor_of(:reg7), do: :nxm_1
|
||||
def vendor_of(:reg8), do: :nxm_1
|
||||
def vendor_of(:reg9), do: :nxm_1
|
||||
def vendor_of(:reg10), do: :nxm_1
|
||||
def vendor_of(:reg11), do: :nxm_1
|
||||
def vendor_of(:reg12), do: :nxm_1
|
||||
def vendor_of(:reg13), do: :nxm_1
|
||||
def vendor_of(:reg14), do: :nxm_1
|
||||
def vendor_of(:reg15), do: :nxm_1
|
||||
def vendor_of(:tun_id), do: :nxm_1
|
||||
def vendor_of(:nx_arp_sha), do: :nxm_1
|
||||
def vendor_of(:nx_arp_tha), do: :nxm_1
|
||||
def vendor_of(:nx_ipv6_src), do: :nxm_1
|
||||
def vendor_of(:nx_ipv6_dst), do: :nxm_1
|
||||
def vendor_of(:nx_icmpv6_type), do: :nxm_1
|
||||
def vendor_of(:nx_icmpv6_code), do: :nxm_1
|
||||
def vendor_of(:nx_ipv6_nd_target), do: :nxm_1
|
||||
def vendor_of(:nx_ipv6_nd_sll), do: :nxm_1
|
||||
def vendor_of(:nx_ipv6_nd_tll), do: :nxm_1
|
||||
def vendor_of(:nx_ip_frag), do: :nxm_1
|
||||
def vendor_of(:nx_ipv6_label), do: :nxm_1
|
||||
def vendor_of(:nx_ip_ecn), do: :nxm_1
|
||||
def vendor_of(:nx_ip_ttl), do: :nxm_1
|
||||
def vendor_of(:nx_mpls_ttl), do: :nxm_1
|
||||
def vendor_of(:tun_src), do: :nxm_1
|
||||
def vendor_of(:tun_dst), do: :nxm_1
|
||||
def vendor_of(:pkt_mark), do: :nxm_1
|
||||
def vendor_of(:dp_hash), do: :nxm_1
|
||||
def vendor_of(:recirc_id), do: :nxm_1
|
||||
def vendor_of(:conj_id), do: :nxm_1
|
||||
def vendor_of(:nx_tun_gbp_id), do: :nxm_1
|
||||
def vendor_of(:nx_tun_gbp_flags), do: :nxm_1
|
||||
def vendor_of(:tun_metadata0), do: :nxm_1
|
||||
def vendor_of(:tun_metadata1), do: :nxm_1
|
||||
def vendor_of(:tun_metadata2), do: :nxm_1
|
||||
def vendor_of(:tun_metadata3), do: :nxm_1
|
||||
def vendor_of(:tun_metadata4), do: :nxm_1
|
||||
def vendor_of(:tun_metadata5), do: :nxm_1
|
||||
def vendor_of(:tun_metadata6), do: :nxm_1
|
||||
def vendor_of(:tun_metadata7), do: :nxm_1
|
||||
def vendor_of(:tun_metadata8), do: :nxm_1
|
||||
def vendor_of(:tun_metadata9), do: :nxm_1
|
||||
def vendor_of(:tun_metadata10), do: :nxm_1
|
||||
def vendor_of(:tun_metadata11), do: :nxm_1
|
||||
def vendor_of(:tun_metadata12), do: :nxm_1
|
||||
def vendor_of(:tun_metadata13), do: :nxm_1
|
||||
def vendor_of(:tun_metadata14), do: :nxm_1
|
||||
def vendor_of(:tun_metadata15), do: :nxm_1
|
||||
def vendor_of(:tun_metadata16), do: :nxm_1
|
||||
def vendor_of(:tun_metadata17), do: :nxm_1
|
||||
def vendor_of(:tun_metadata18), do: :nxm_1
|
||||
def vendor_of(:tun_metadata19), do: :nxm_1
|
||||
def vendor_of(:tun_metadata20), do: :nxm_1
|
||||
def vendor_of(:tun_metadata21), do: :nxm_1
|
||||
def vendor_of(:tun_metadata22), do: :nxm_1
|
||||
def vendor_of(:tun_metadata23), do: :nxm_1
|
||||
def vendor_of(:tun_metadata24), do: :nxm_1
|
||||
def vendor_of(:tun_metadata25), do: :nxm_1
|
||||
def vendor_of(:tun_metadata26), do: :nxm_1
|
||||
def vendor_of(:tun_metadata27), do: :nxm_1
|
||||
def vendor_of(:tun_metadata28), do: :nxm_1
|
||||
def vendor_of(:tun_metadata29), do: :nxm_1
|
||||
def vendor_of(:tun_metadata30), do: :nxm_1
|
||||
def vendor_of(:tun_metadata31), do: :nxm_1
|
||||
def vendor_of(:tun_metadata32), do: :nxm_1
|
||||
def vendor_of(:tun_metadata33), do: :nxm_1
|
||||
def vendor_of(:tun_metadata34), do: :nxm_1
|
||||
def vendor_of(:tun_metadata35), do: :nxm_1
|
||||
def vendor_of(:tun_metadata36), do: :nxm_1
|
||||
def vendor_of(:tun_metadata37), do: :nxm_1
|
||||
def vendor_of(:tun_metadata38), do: :nxm_1
|
||||
def vendor_of(:tun_metadata39), do: :nxm_1
|
||||
def vendor_of(:tun_metadata40), do: :nxm_1
|
||||
def vendor_of(:tun_metadata41), do: :nxm_1
|
||||
def vendor_of(:tun_metadata42), do: :nxm_1
|
||||
def vendor_of(:tun_metadata43), do: :nxm_1
|
||||
def vendor_of(:tun_metadata44), do: :nxm_1
|
||||
def vendor_of(:tun_metadata45), do: :nxm_1
|
||||
def vendor_of(:tun_metadata46), do: :nxm_1
|
||||
def vendor_of(:tun_metadata47), do: :nxm_1
|
||||
def vendor_of(:tun_metadata48), do: :nxm_1
|
||||
def vendor_of(:tun_metadata49), do: :nxm_1
|
||||
def vendor_of(:tun_metadata50), do: :nxm_1
|
||||
def vendor_of(:tun_metadata51), do: :nxm_1
|
||||
def vendor_of(:tun_metadata52), do: :nxm_1
|
||||
def vendor_of(:tun_metadata53), do: :nxm_1
|
||||
def vendor_of(:tun_metadata54), do: :nxm_1
|
||||
def vendor_of(:tun_metadata55), do: :nxm_1
|
||||
def vendor_of(:tun_metadata56), do: :nxm_1
|
||||
def vendor_of(:tun_metadata57), do: :nxm_1
|
||||
def vendor_of(:tun_metadata58), do: :nxm_1
|
||||
def vendor_of(:tun_metadata59), do: :nxm_1
|
||||
def vendor_of(:tun_metadata60), do: :nxm_1
|
||||
def vendor_of(:tun_metadata61), do: :nxm_1
|
||||
def vendor_of(:tun_metadata62), do: :nxm_1
|
||||
def vendor_of(:tun_metadata63), do: :nxm_1
|
||||
def vendor_of(:tun_flags), do: :nxm_1
|
||||
def vendor_of(:ct_state), do: :nxm_1
|
||||
def vendor_of(:ct_zone), do: :nxm_1
|
||||
def vendor_of(:ct_mark), do: :nxm_1
|
||||
def vendor_of(:ct_label), do: :nxm_1
|
||||
def vendor_of(:tun_ipv6_src), do: :nxm_1
|
||||
def vendor_of(:tun_ipv6_dst), do: :nxm_1
|
||||
def vendor_of(:xxreg0), do: :nxm_1
|
||||
def vendor_of(:xxreg1), do: :nxm_1
|
||||
def vendor_of(:xxreg2), do: :nxm_1
|
||||
def vendor_of(:xxreg3), do: :nxm_1
|
||||
def vendor_of(:xxreg4), do: :nxm_1
|
||||
def vendor_of(:xxreg5), do: :nxm_1
|
||||
def vendor_of(:xxreg6), do: :nxm_1
|
||||
def vendor_of(:xxreg7), do: :nxm_1
|
||||
def vendor_of(:ct_ip_proto), do: :nxm_1
|
||||
def vendor_of(:ct_ipv4_src), do: :nxm_1
|
||||
def vendor_of(:ct_ipv4_dst), do: :nxm_1
|
||||
def vendor_of(:ct_ipv6_src), do: :nxm_1
|
||||
def vendor_of(:ct_ipv6_dst), do: :nxm_1
|
||||
def vendor_of(:ct_tp_src), do: :nxm_1
|
||||
def vendor_of(:ct_tp_dst), do: :nxm_1
|
||||
|
||||
# OpenFlow Basic
|
||||
def vendor_of(:in_port), do: :openflow_basic
|
||||
def vendor_of(:in_phy_port), do: :openflow_basic
|
||||
def vendor_of(:metadata), do: :openflow_basic
|
||||
def vendor_of(:eth_dst), do: :openflow_basic
|
||||
def vendor_of(:eth_src), do: :openflow_basic
|
||||
def vendor_of(:eth_type), do: :openflow_basic
|
||||
def vendor_of(:vlan_vid), do: :openflow_basic
|
||||
def vendor_of(:vlan_pcp), do: :openflow_basic
|
||||
def vendor_of(:ip_dscp), do: :openflow_basic
|
||||
def vendor_of(:ip_ecn), do: :openflow_basic
|
||||
def vendor_of(:ip_proto), do: :openflow_basic
|
||||
def vendor_of(:ipv4_src), do: :openflow_basic
|
||||
def vendor_of(:ipv4_dst), do: :openflow_basic
|
||||
def vendor_of(:tcp_src), do: :openflow_basic
|
||||
def vendor_of(:tcp_dst), do: :openflow_basic
|
||||
def vendor_of(:udp_src), do: :openflow_basic
|
||||
def vendor_of(:udp_dst), do: :openflow_basic
|
||||
def vendor_of(:sctp_src), do: :openflow_basic
|
||||
def vendor_of(:sctp_dst), do: :openflow_basic
|
||||
def vendor_of(:icmpv4_type), do: :openflow_basic
|
||||
def vendor_of(:icmpv4_code), do: :openflow_basic
|
||||
def vendor_of(:arp_op), do: :openflow_basic
|
||||
def vendor_of(:arp_spa), do: :openflow_basic
|
||||
def vendor_of(:arp_tpa), do: :openflow_basic
|
||||
def vendor_of(:arp_sha), do: :openflow_basic
|
||||
def vendor_of(:arp_tha), do: :openflow_basic
|
||||
def vendor_of(:ipv6_src), do: :openflow_basic
|
||||
def vendor_of(:ipv6_dst), do: :openflow_basic
|
||||
def vendor_of(:ipv6_flabel), do: :openflow_basic
|
||||
def vendor_of(:icmpv6_type), do: :openflow_basic
|
||||
def vendor_of(:icmpv6_code), do: :openflow_basic
|
||||
def vendor_of(:ipv6_nd_target), do: :openflow_basic
|
||||
def vendor_of(:ipv6_nd_sll), do: :openflow_basic
|
||||
def vendor_of(:ipv6_nd_tll), do: :openflow_basic
|
||||
def vendor_of(:mpls_label), do: :openflow_basic
|
||||
def vendor_of(:mpls_tc), do: :openflow_basic
|
||||
def vendor_of(:mpls_bos), do: :openflow_basic
|
||||
def vendor_of(:pbb_isid), do: :openflow_basic
|
||||
def vendor_of(:tunnel_id), do: :openflow_basic
|
||||
def vendor_of(:ipv6_exthdr), do: :openflow_basic
|
||||
def vendor_of(:pbb_uca), do: :openflow_basic
|
||||
def vendor_of(:packet_type), do: :openflow_basic
|
||||
def vendor_of(:gre_flags), do: :openflow_basic
|
||||
def vendor_of(:gre_ver), do: :openflow_basic
|
||||
def vendor_of(:gre_protocol), do: :openflow_basic
|
||||
def vendor_of(:gre_key), do: :openflow_basic
|
||||
def vendor_of(:gre_seqnum), do: :openflow_basic
|
||||
def vendor_of(:lisp_flags), do: :openflow_basic
|
||||
def vendor_of(:lisp_nonce), do: :openflow_basic
|
||||
def vendor_of(:lisp_id), do: :openflow_basic
|
||||
def vendor_of(:vxlan_flags), do: :openflow_basic
|
||||
def vendor_of(:vxlan_vni), do: :openflow_basic
|
||||
def vendor_of(:mpls_data_first_nibble), do: :openflow_basic
|
||||
def vendor_of(:mpls_ach_version), do: :openflow_basic
|
||||
def vendor_of(:mpls_ach_channel), do: :openflow_basic
|
||||
def vendor_of(:mpls_pw_metadata), do: :openflow_basic
|
||||
def vendor_of(:mpls_cw_flags), do: :openflow_basic
|
||||
def vendor_of(:mpls_cw_fragment), do: :openflow_basic
|
||||
def vendor_of(:mpls_cw_len), do: :openflow_basic
|
||||
def vendor_of(:mpls_cw_seq_num), do: :openflow_basic
|
||||
def vendor_of(:gtpu_flags), do: :openflow_basic
|
||||
def vendor_of(:gtpu_ver), do: :openflow_basic
|
||||
def vendor_of(:gtpu_msg_type), do: :openflow_basic
|
||||
def vendor_of(:gtpu_teid), do: :openflow_basic
|
||||
def vendor_of(:gtpu_extn_hdr), do: :openflow_basic
|
||||
def vendor_of(:gtpu_extn_udp_port), do: :openflow_basic
|
||||
def vendor_of(:gtpu_extn_sci), do: :openflow_basic
|
||||
|
||||
# Packet Register
|
||||
def vendor_of(:xreg0), do: :packet_register
|
||||
def vendor_of(:xreg1), do: :packet_register
|
||||
def vendor_of(:xreg2), do: :packet_register
|
||||
def vendor_of(:xreg3), do: :packet_register
|
||||
def vendor_of(:xreg4), do: :packet_register
|
||||
def vendor_of(:xreg5), do: :packet_register
|
||||
def vendor_of(:xreg6), do: :packet_register
|
||||
def vendor_of(:xreg7), do: :packet_register
|
||||
|
||||
# Nicira Ext Match
|
||||
def vendor_of(:nsh_flags), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_mdtype), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_np), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_spi), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_si), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_c1), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_c2), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_c3), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_c4), do: :nicira_ext_match
|
||||
|
||||
# ONF Ext Match
|
||||
def vendor_of(:onf_tcp_flags), do: :onf_ext_match
|
||||
def vendor_of(:onf_actset_output), do: :onf_ext_match
|
||||
def vendor_of(:onf_pbb_uca), do: :onf_ext_match
|
||||
|
||||
# NXM0
|
||||
def format_of(:nx_in_port), do: {:be16, :openflow10_port}
|
||||
def format_of(:nx_eth_dst), do: {:mac, :ethernet}
|
||||
def format_of(:nx_eth_src), do: {:mac, :ethernet}
|
||||
def format_of(:nx_eth_type), do: {:be16, :hexadecimal}
|
||||
def format_of(:nx_vlan_tci), do: {:be16, :hexadecimal}
|
||||
def format_of(:nx_ip_tos), do: {:u8, :decimal}
|
||||
def format_of(:nx_ip_proto), do: {:u8, :decimal}
|
||||
def format_of(:nx_ipv4_src), do: {:be32, :ipv4}
|
||||
def format_of(:nx_ipv4_dst), do: {:be32, :ipv4}
|
||||
def format_of(:nx_tcp_src), do: {:be16, :decimal}
|
||||
def format_of(:nx_tcp_dst), do: {:be16, :decimal}
|
||||
def format_of(:nx_udp_src), do: {:be16, :decimal}
|
||||
def format_of(:nx_udp_dst), do: {:be16, :decimal}
|
||||
def format_of(:nx_icmpv4_type), do: {:u8, :decimal}
|
||||
def format_of(:nx_icmpv4_code), do: {:u8, :decimal}
|
||||
def format_of(:nx_arp_op), do: {:be16, :decimal}
|
||||
def format_of(:nx_arp_spa), do: {:be32, :ipv4}
|
||||
def format_of(:nx_arp_tpa), do: {:be32, :ipv4}
|
||||
def format_of(:nx_tcp_flags), do: {:be16, :tcp_flags}
|
||||
|
||||
# NXM1
|
||||
def format_of(:reg0), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg1), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg2), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg3), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg4), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg5), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg6), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg7), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg8), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg9), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg10), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg11), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg12), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg13), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg14), do: {:be32, :hexadecimal}
|
||||
def format_of(:reg15), do: {:be32, :hexadecimal}
|
||||
def format_of(:tun_id), do: {:be64, :hexadecimal}
|
||||
def format_of(:nx_arp_sha), do: {:mac, :ethernet}
|
||||
def format_of(:nx_arp_tha), do: {:mac, :ethernet}
|
||||
def format_of(:nx_ipv6_src), do: {:be128, :ipv6}
|
||||
def format_of(:nx_ipv6_dst), do: {:be128, :ipv6}
|
||||
def format_of(:nx_icmpv6_type), do: {:u8, :decimal}
|
||||
def format_of(:nx_icmpv6_code), do: {:u8, :decimal}
|
||||
def format_of(:nx_ipv6_nd_target), do: {:be128, :ipv6}
|
||||
def format_of(:nx_ipv6_nd_sll), do: {:mac, :ethernet}
|
||||
def format_of(:nx_ipv6_nd_tll), do: {:mac, :ethernet}
|
||||
def format_of(:nx_ip_frag), do: {:u8, :decimal}
|
||||
def format_of(:nx_ipv6_label), do: {:be32, :hexadecimal}
|
||||
def format_of(:nx_ip_ecn), do: {:u8, :decimal}
|
||||
def format_of(:nx_ip_ttl), do: {:u8, :decimal}
|
||||
def format_of(:nx_mpls_ttl), do: {:u8, :decimal}
|
||||
def format_of(:tun_src), do: {:be32, :ipv4}
|
||||
def format_of(:tun_dst), do: {:be32, :ipv4}
|
||||
def format_of(:pkt_mark), do: {:be32, :hexadecimal}
|
||||
def format_of(:dp_hash), do: {:be32, :hexadecimal}
|
||||
def format_of(:recirc_id), do: {:be32, :hexadecimal}
|
||||
def format_of(:conj_id), do: {:be32, :hexadecimal}
|
||||
def format_of(:nx_tun_gbp_id), do: {:be16, :decimal}
|
||||
def format_of(:nx_tun_gbp_flags), do: {:u8, :decimal}
|
||||
def format_of(:tun_metadata0), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata1), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata2), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata3), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata4), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata5), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata6), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata7), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata8), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata9), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata10), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata11), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata12), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata13), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata14), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata15), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata16), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata17), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata18), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata19), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata20), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata21), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata22), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata23), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata24), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata25), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata26), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata27), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata28), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata29), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata30), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata31), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata32), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata33), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata34), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata35), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata36), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata37), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata38), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata39), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata40), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata41), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata42), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata43), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata44), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata45), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata46), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata47), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata48), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata49), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata50), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata51), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata52), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata53), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata54), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata55), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata56), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata57), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata58), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata59), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata60), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata61), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata62), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_metadata63), do: {:dynamic, :bytes}
|
||||
def format_of(:tun_flags), do: {:be16, :decimal}
|
||||
def format_of(:ct_state), do: {:be32, :ct_state}
|
||||
def format_of(:ct_zone), do: {:be16, :hexadecimal}
|
||||
def format_of(:ct_mark), do: {:be32, :hexadecimal}
|
||||
def format_of(:ct_label), do: {:be128, :hexadecimal}
|
||||
def format_of(:tun_ipv6_src), do: {:be128, :ipv6}
|
||||
def format_of(:tun_ipv6_dst), do: {:be128, :ipv6}
|
||||
def format_of(:xxreg0), do: {:be128, :hexadecimal}
|
||||
def format_of(:xxreg1), do: {:be128, :hexadecimal}
|
||||
def format_of(:xxreg2), do: {:be128, :hexadecimal}
|
||||
def format_of(:xxreg3), do: {:be128, :hexadecimal}
|
||||
def format_of(:xxreg4), do: {:be128, :hexadecimal}
|
||||
def format_of(:xxreg5), do: {:be128, :hexadecimal}
|
||||
def format_of(:xxreg6), do: {:be128, :hexadecimal}
|
||||
def format_of(:xxreg7), do: {:be128, :hexadecimal}
|
||||
def format_of(:ct_ip_proto), do: {:u8, :decimal}
|
||||
def format_of(:ct_ipv4_src), do: {:be32, :ipv4}
|
||||
def format_of(:ct_ipv4_dst), do: {:be32, :ipv4}
|
||||
def format_of(:ct_ipv6_src), do: {:be128, :ipv6}
|
||||
def format_of(:ct_ipv6_dst), do: {:be128, :ipv6}
|
||||
def format_of(:ct_tp_src), do: {:be16, :decimal}
|
||||
def format_of(:ct_tp_dst), do: {:be16, :decimal}
|
||||
|
||||
# OpenFlow Basic
|
||||
def format_of(:in_port), do: {:be32, :openflow13_port}
|
||||
def format_of(:in_phy_port), do: {:be32, :openflow13_port}
|
||||
def format_of(:metadata), do: {:be64, :hexadecimal}
|
||||
def format_of(:eth_dst), do: {:mac, :ethernet}
|
||||
def format_of(:eth_src), do: {:mac, :ethernet}
|
||||
def format_of(:eth_type), do: {:be16, :hexadecimal}
|
||||
def format_of(:vlan_vid), do: {:be16, :hexadecimal}
|
||||
def format_of(:vlan_pcp), do: {:u8, :decimal}
|
||||
def format_of(:ip_dscp), do: {:u8, :decimal}
|
||||
def format_of(:ip_ecn), do: {:u8, :decimal}
|
||||
def format_of(:ip_proto), do: {:u8, :decimal}
|
||||
def format_of(:ipv4_src), do: {:be32, :ipv4}
|
||||
def format_of(:ipv4_dst), do: {:be32, :ipv4}
|
||||
def format_of(:tcp_src), do: {:be16, :decimal}
|
||||
def format_of(:tcp_dst), do: {:be16, :decimal}
|
||||
def format_of(:udp_src), do: {:be16, :decimal}
|
||||
def format_of(:udp_dst), do: {:be16, :decimal}
|
||||
def format_of(:sctp_src), do: {:be16, :decimal}
|
||||
def format_of(:sctp_dst), do: {:be16, :decimal}
|
||||
def format_of(:icmpv4_type), do: {:u8, :decimal}
|
||||
def format_of(:icmpv4_code), do: {:u8, :decimal}
|
||||
def format_of(:arp_op), do: {:be16, :decimal}
|
||||
def format_of(:arp_spa), do: {:be32, :ipv4}
|
||||
def format_of(:arp_tpa), do: {:be32, :ipv4}
|
||||
def format_of(:arp_sha), do: {:mac, :ethernet}
|
||||
def format_of(:arp_tha), do: {:mac, :ethernet}
|
||||
def format_of(:ipv6_src), do: {:be128, :ipv6}
|
||||
def format_of(:ipv6_dst), do: {:be128, :ipv6}
|
||||
def format_of(:ipv6_flabel), do: {:be32, :hexadecimal}
|
||||
def format_of(:icmpv6_type), do: {:u8, :decimal}
|
||||
def format_of(:icmpv6_code), do: {:u8, :decimal}
|
||||
def format_of(:ipv6_nd_target), do: {:be128, :ipv6}
|
||||
def format_of(:ipv6_nd_sll), do: {:mac, :ethernet}
|
||||
def format_of(:ipv6_nd_tll), do: {:mac, :ethernet}
|
||||
def format_of(:mpls_label), do: {:be32, :decimal}
|
||||
def format_of(:mpls_tc), do: {:u8, :decimal}
|
||||
def format_of(:mpls_bos), do: {:u8, :decimal}
|
||||
def format_of(:pbb_isid), do: {:u24, :decimal}
|
||||
def format_of(:tunnel_id), do: {:be64, :hexadecimal}
|
||||
def format_of(:ipv6_exthdr), do: {:be16, :ipv6exthdr_flags}
|
||||
def format_of(:pbb_uca), do: {:u8, :decimal}
|
||||
def format_of(:packet_type), do: {:be32, :decimal}
|
||||
def format_of(:gre_flags), do: {:be16, :decimal}
|
||||
def format_of(:gre_ver), do: {:u8, :decimal}
|
||||
def format_of(:gre_protocol), do: {:be16, :decimal}
|
||||
def format_of(:gre_key), do: {:be32, :decimal}
|
||||
def format_of(:gre_seqnum), do: {:be32, :decimal}
|
||||
def format_of(:lisp_flags), do: {:u8, :decimal}
|
||||
def format_of(:lisp_nonce), do: {:u24, :decimal}
|
||||
def format_of(:lisp_id), do: {:be32, :decimal}
|
||||
def format_of(:vxlan_flags), do: {:u8, :decimal}
|
||||
def format_of(:vxlan_vni), do: {:u24, :decimal}
|
||||
def format_of(:mpls_data_first_nibble), do: {:u8, :decimal}
|
||||
def format_of(:mpls_ach_version), do: {:u8, :decimal}
|
||||
def format_of(:mpls_ach_channel), do: {:be16, :decimal}
|
||||
def format_of(:mpls_pw_metadata), do: {:u8, :decimal}
|
||||
def format_of(:mpls_cw_flags), do: {:u8, :decimal}
|
||||
def format_of(:mpls_cw_fragment), do: {:u8, :decimal}
|
||||
def format_of(:mpls_cw_len), do: {:u8, :decimal}
|
||||
def format_of(:mpls_cw_seq_num), do: {:be16, :decimal}
|
||||
def format_of(:gtpu_flags), do: {:u8, :decimal}
|
||||
def format_of(:gtpu_ver), do: {:u8, :decimal}
|
||||
def format_of(:gtpu_msg_type), do: {:u8, :decimal}
|
||||
def format_of(:gtpu_teid), do: {:be32, :decimal}
|
||||
def format_of(:gtpu_extn_hdr), do: {:u8, :decimal}
|
||||
def format_of(:gtpu_extn_udp_port), do: {:be16, :decimal}
|
||||
def format_of(:gtpu_extn_sci), do: {:be16, :decimal}
|
||||
|
||||
# Packet Register
|
||||
def format_of(:xreg0), do: {:be64, :hexadecimal}
|
||||
def format_of(:xreg1), do: {:be64, :hexadecimal}
|
||||
def format_of(:xreg2), do: {:be64, :hexadecimal}
|
||||
def format_of(:xreg3), do: {:be64, :hexadecimal}
|
||||
def format_of(:xreg4), do: {:be64, :hexadecimal}
|
||||
def format_of(:xreg5), do: {:be64, :hexadecimal}
|
||||
def format_of(:xreg6), do: {:be64, :hexadecimal}
|
||||
def format_of(:xreg7), do: {:be64, :hexadecimal}
|
||||
|
||||
# Nicira Ext Match
|
||||
def format_of(:nsh_flags), do: {:u8, :decimal}
|
||||
def format_of(:nsh_mdtype), do: {:u8, :decimal}
|
||||
def format_of(:nsh_np), do: {:u8, :decimal}
|
||||
def format_of(:nsh_spi), do: {:be32, :decimal}
|
||||
def format_of(:nsh_si), do: {:be32, :decimal}
|
||||
def format_of(:nsh_c1), do: {:be32, :decimal}
|
||||
def format_of(:nsh_c2), do: {:be32, :decimal}
|
||||
def format_of(:nsh_c3), do: {:be32, :decimal}
|
||||
def format_of(:nsh_c4), do: {:be32, :decimal}
|
||||
|
||||
# ONF Ext Match
|
||||
def format_of(:onf_tcp_flags), do: {:be16, :tcp_flags}
|
||||
def format_of(:onf_actset_output), do: {:be32, :openflow13_port}
|
||||
def format_of(:onf_pbb_uca), do: {:u8, :decimal}
|
||||
|
||||
# Formatting = decimal
|
||||
def formatting(<<value::8>>, :u8, :decimal), do: value
|
||||
def formatting(value, :u8, :decimal) when is_integer(value), do: <<value::8>>
|
||||
def formatting(<<value::16>>, :be16, :decimal), do: value
|
||||
def formatting(value, :be16, :decimal) when is_integer(value), do: <<value::16>>
|
||||
def formatting(<<value::24>>, :u24, :decimal), do: value
|
||||
def formatting(value, :u24, :decimal) when is_integer(value), do: <<value::24>>
|
||||
def formatting(<<value::32>>, :be32, :decimal), do: value
|
||||
def formatting(value, :be32, :decimal) when is_integer(value), do: <<value::32>>
|
||||
def formatting(<<value::64>>, :be64, :decimal), do: value
|
||||
def formatting(value, :be64, :decimal) when is_integer(value), do: <<value::64>>
|
||||
def formatting(<<value::128>>, :be128, :decimal), do: value
|
||||
def formatting(value, :be128, :decimal) when is_integer(value), do: <<value::128>>
|
||||
|
||||
# Formatting = hexadecimal
|
||||
def formatting(<<value::16>>, :be16, :hexadecimal), do: value
|
||||
def formatting(value, :be16, :hexadecimal) when is_integer(value), do: <<value::16>>
|
||||
|
||||
def formatting(<<value::24>>, :u24, :hexadecimal), do: value
|
||||
def formatting(value, :u24, :hexadecimal) when is_integer(value), do: <<value::24>>
|
||||
|
||||
def formatting(<<value::32>>, :be32, :hexadecimal), do: value
|
||||
def formatting(value, :be32, :hexadecimal) when is_integer(value), do: <<value::32>>
|
||||
|
||||
def formatting(<<value::64>>, :be64, :hexadecimal), do: value
|
||||
def formatting(value, :be64, :hexadecimal) when is_integer(value), do: <<value::64>>
|
||||
|
||||
def formatting(<<value::128>>, :be128, :hexadecimal), do: value
|
||||
def formatting(value, :be128, :hexadecimal) when is_integer(value), do: <<value::128>>
|
||||
|
||||
# Formatting = ethernet
|
||||
def formatting(<<value::48-bits>>, :mac, :ethernet), do: Openflow.Utils.to_hex_string(value)
|
||||
def formatting(value, :mac, :ethernet), do: <<(String.to_integer(value, 16))::48>>
|
||||
|
||||
# Formatting = IPv4
|
||||
def formatting(<<a1, a2, a3, a4>>, :be32, :ipv4), do: {a1, a2, a3, a4}
|
||||
def formatting({a1, a2, a3, a4}, :be32, :ipv4), do: <<a1, a2, a3, a4>>
|
||||
|
||||
# Formatting = IPv6
|
||||
def formatting(<<a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16>>, :be128, :ipv6) do
|
||||
{a1, a2, a3, a4, a5, a6, a7, a8}
|
||||
end
|
||||
def formatting({a1, a2, a3, a4, a5, a6, a7, a8},:be128, :ipv6) do
|
||||
<<a1::16, a2::16, a3::16, a4::16, a5::16, a6::16, a7::16, a8::16>>
|
||||
end
|
||||
|
||||
# Formatting = OpenFlow 1.0 port
|
||||
def formatting(<<value::16>>, :be16, :openflow10_port) do
|
||||
try do
|
||||
Openflow.Enums.to_atom(value, :openflow10_port_no)
|
||||
catch
|
||||
:bad_enum -> value
|
||||
end
|
||||
end
|
||||
def formatting(value, :be16, :openflow10_port) do
|
||||
port_no =
|
||||
try do
|
||||
Openflow.Enums.to_int(value, :openflow10_port_no)
|
||||
catch
|
||||
:bad_enum -> value
|
||||
end
|
||||
<<port_no::16>>
|
||||
end
|
||||
|
||||
# Formatting = OpenFlow 1.3 port
|
||||
def formatting(<<value::32>>, :be32, :openflow13_port) do
|
||||
try do
|
||||
Openflow.Enums.to_atom(value, :openflow13_port_no)
|
||||
catch
|
||||
:bad_enum -> value
|
||||
end
|
||||
end
|
||||
def formatting(value, :be32, :openflow13_port) do
|
||||
port_no =
|
||||
try do
|
||||
Openflow.Enums.to_int(value, :openflow13_port_no)
|
||||
catch
|
||||
:bad_enum -> value
|
||||
end
|
||||
<<port_no::32>>
|
||||
end
|
||||
|
||||
# TCP flags
|
||||
def formatting(<<value::16>>, :be16, :tcp_flags) do
|
||||
Openflow.Enums.int_to_flags(value, :tcp_flags)
|
||||
end
|
||||
def formatting(value, :be16, :tcp_flags) do
|
||||
<<(Openflow.Enums.flags_to_int(value, :tcp_flags))::16>>
|
||||
end
|
||||
|
||||
# CT State
|
||||
def formatting(<<value::32>>, :be32, :ct_state) do
|
||||
Openflow.Enums.int_to_flags(value, :ct_state_flags)
|
||||
end
|
||||
def formatting(value, :be32, :ct_state) do
|
||||
<<(Openflow.Enums.flags_to_int(value, :ct_state_flags))::32>>
|
||||
end
|
||||
|
||||
# CT State
|
||||
def formatting(<<value::16>>, :be16, :ipv6exthdr_flags) do
|
||||
Openflow.Enums.int_to_flags(value, :ipv6exthdr_flags)
|
||||
end
|
||||
def formatting(value, :be16, :ipv6exthdr_flags) do
|
||||
<<(Openflow.Enums.flags_to_int(value, :ipv6exthdr_flags))::16>>
|
||||
end
|
||||
|
||||
# Other
|
||||
def formatting(value, _, _) do
|
||||
value
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue