diff --git a/lib/openflow/multipart/table_features/body.ex b/lib/openflow/multipart/table_features/body.ex index 3399a06..b1b89d9 100644 --- a/lib/openflow/multipart/table_features/body.ex +++ b/lib/openflow/multipart/table_features/body.ex @@ -18,7 +18,9 @@ defmodule Openflow.Multipart.TableFeatures.Body do write_setfield: nil, write_setfield_miss: nil, apply_setfield: nil, - apply_setfield_miss: nil + apply_setfield_miss: nil, + experimenter: nil, + experimenter_miss: nil alias __MODULE__ @@ -40,6 +42,8 @@ defmodule Openflow.Multipart.TableFeatures.Body do @write_setfield_miss 13 @apply_setfield 14 @apply_setfield_miss 15 + @experimenter 0xFFFE + @experimenter_miss 0xFFFF @prop_keys [ :instructions, @@ -55,7 +59,9 @@ defmodule Openflow.Multipart.TableFeatures.Body do :write_setfield, :write_setfield_miss, :apply_setfield, - :apply_setfield_miss + :apply_setfield_miss, + :experimenter, + :experimenter_miss ] def new(options) do @@ -79,7 +85,9 @@ defmodule Openflow.Multipart.TableFeatures.Body do write_setfield: options[:write_setfield], write_setfield_miss: options[:write_setfield_miss], apply_setfield: options[:apply_setfield], - apply_setfield_miss: options[:apply_setfield_miss] + apply_setfield_miss: options[:apply_setfield_miss], + experimenter: options[:experimenter], + experimenter_miss: options[:experimenter_miss] } end @@ -111,7 +119,7 @@ defmodule Openflow.Multipart.TableFeatures.Body do name_bin::size(@max_table_name_len)-bytes, metadata_match::64, metadata_write::64, config_int::32, max_entries::32, props_bin::bytes>> ) do - name = Openflow.Utils.decode_string(name_bin) + name = hd(String.split(name_bin, <<0>>, parts: 2)) config = Openflow.Enums.int_to_flags(config_int, :table_config) body = %Body{ @@ -142,7 +150,7 @@ defmodule Openflow.Multipart.TableFeatures.Body do } = table config_int = Openflow.Enums.flags_to_int(config, :table_config) - name_bin = Openflow.Utils.encode_string(name, @max_table_name_len) + name_bin = String.pad_trailing(name, @max_table_name_len, <<0>>) <> @@ -171,7 +179,7 @@ defmodule Openflow.Multipart.TableFeatures.Body do pad_length = Openflow.Utils.pad_length(length, 8) value_length = length - @prop_header_length <> = tail - next_tables = for <>, do: table_id + next_tables = :erlang.binary_to_list(next_tables_bin) type = Openflow.Enums.to_atom(type_int, :table_feature_prop_type) body @@ -208,9 +216,13 @@ defmodule Openflow.Multipart.TableFeatures.Body do |> decode_props(rest) end - defp decode_props(body, <<_type_int::16, length::16, tail::bytes>>) do + defp decode_props( + body, + <> + ) + when type_int == @experimenter or type_int == @experimenter_miss do pad_length = Openflow.Utils.pad_length(length, 8) - value_length = length - @prop_header_length + value_length = length - 12 <<_::size(value_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail decode_props(body, rest) end @@ -230,7 +242,7 @@ defmodule Openflow.Multipart.TableFeatures.Body do defp encode_props(acc, table, [type | rest]) when type == :next_tables or type == :next_tables_miss do type_int = Openflow.Enums.to_int(type, :table_feature_prop_type) - next_tables_bin = to_string(Map.get(table, type)) + next_tables_bin = :erlang.list_to_binary(Map.get(table, type)) length = @prop_header_length + byte_size(next_tables_bin) pad_length = Openflow.Utils.pad_length(length, 8) body = <> @@ -260,6 +272,10 @@ defmodule Openflow.Multipart.TableFeatures.Body do encode_props(<>, table, rest) end + defp encode_props(acc, table, [_type | rest]) do + encode_props(acc, table, rest) + end + defp decode_instructions(acc, ""), do: Enum.reverse(acc) defp decode_instructions(acc, <<0xFFFF::16, _::16, exp_id::32, rest::bytes>>) do diff --git a/lib/openflow/multipart/table_features/reply.ex b/lib/openflow/multipart/table_features/reply.ex index f44f4fa..3e53960 100644 --- a/lib/openflow/multipart/table_features/reply.ex +++ b/lib/openflow/multipart/table_features/reply.ex @@ -12,24 +12,13 @@ defmodule Openflow.Multipart.TableFeatures.Reply do alias __MODULE__ alias Openflow.Multipart.TableFeatures.Body - def ofp_type, do: 18 - - def new(tables \\ []) do - %Reply{tables: tables} - end + def ofp_type, do: 19 def read(<>) do tables = Body.read(tables_bin) %Reply{tables: tables} end - def to_binary(msg) do - header_bin = Openflow.Multipart.Reply.header(msg) - %Reply{tables: tables} = msg - tables_bin = Openflow.Multipart.TableFeatures.Body.to_binary(tables) - <> - end - def append_body(%Reply{tables: tables} = message, %Reply{flags: [:more], tables: continue}) do %{message | tables: [continue | tables]} end diff --git a/lib/openflow/multipart/table_features/request.ex b/lib/openflow/multipart/table_features/request.ex index 451977d..dbcd331 100644 --- a/lib/openflow/multipart/table_features/request.ex +++ b/lib/openflow/multipart/table_features/request.ex @@ -16,6 +16,7 @@ defmodule Openflow.Multipart.TableFeatures.Request do def new(options \\ []) do %Request{ + flags: options[:flags] || [], xid: options[:xid] || 0, tables: options[:tables] || [] } @@ -32,17 +33,4 @@ defmodule Openflow.Multipart.TableFeatures.Request do tables_bin = Openflow.Multipart.TableFeatures.Body.to_binary(tables) <> end - - def append_body(%Request{tables: tables} = message, %Request{flags: [:more], tables: continue}) do - %{message | tables: [continue | tables]} - end - - def append_body(%Request{tables: tables} = message, %Request{flags: [], tables: continue}) do - new_tables = - [continue | tables] - |> Enum.reverse() - |> List.flatten() - - %{message | tables: new_tables} - end end diff --git a/test/lib/openflow/ofp_tables_features_test.exs b/test/lib/openflow/ofp_tables_features_test.exs new file mode 100644 index 0000000..46157f8 --- /dev/null +++ b/test/lib/openflow/ofp_tables_features_test.exs @@ -0,0 +1,31 @@ +defmodule OfpTableFeaturesTest do + use ExUnit.Case + + describe "Openflow.Multipart.Table.Request" do + test "with default values" do + table_features = + "test/packet_data/4-55-ofp_table_features_request.packet" + |> File.read!() + |> Openflow.read() + |> Kernel.elem(1) + + table_features + |> Map.to_list() + |> Openflow.Multipart.TableFeatures.Request.new() + |> Openflow.to_binary() + |> Openflow.read() + |> Kernel.elem(1) + |> Kernel.==(table_features) + |> assert() + end + end + + describe "Openflow.Multipart.Table.Reply" do + test "with default values" do + "test/packet_data/4-56-ofp_table_features_reply.packet" + |> File.read!() + |> Openflow.read() + |> Kernel.elem(1) + end + end +end