defmodule Openflow.NxPacketIn2 do defstruct( version: 4, xid: 0, datapath_id: "", aux_id: 0, # packet_in properties: packet: nil, full_len: nil, buffer_id: nil, table_id: nil, cookie: nil, reason: nil, metadata: nil, userdata: nil, # continuation properties: continuation_bridge: "", continuation_stack: [], continuation_conntracked: false, continuation_table_id: nil, continuation_cookie: nil, continuation_actions: [], continuation_action_set: nil ) alias __MODULE__ @experimenter 0x00002320 @nx_type 30 @packet 0 @full_len 1 @buffer_id 2 @table_id 3 @cookie 4 @reason 5 @metadata 6 @userdata 7 @continuation 8 @nxcpt_bridge 0x8000 @nxcpt_stack 0x8001 @nxcpt_mirrors 0x8002 @nxcpt_conntracked 0x8003 @nxcpt_table_id 0x8004 @nxcpt_cookie 0x8005 @nxcpt_actions 0x8006 @nxcpt_action_set 0x8007 @prop_header_length 4 def ofp_type, do: 4 def read(<<@experimenter::32, @nx_type::32, props_bin::bytes>>) do %NxPacketIn2{} |> decode_props(props_bin) end ## private functions defp decode_props(pktin, ""), do: pktin defp decode_props(pktin, <<@packet::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) packet_length = length - @prop_header_length <> = tail decode_props(%{pktin|packet: packet}, rest) end defp decode_props(pktin, <<@full_len::16, _length::16, full_len::32, rest::bytes>>) do decode_props(%{pktin|full_len: full_len}, rest) end defp decode_props(pktin, <<@buffer_id::16, _length::16, buffer_id::32, rest::bytes>>) do decode_props(%{pktin|buffer_id: buffer_id}, rest) end defp decode_props(pktin, <<@table_id::16, _length::16, table_id::8, _::24, rest::bytes>>) do decode_props(%{pktin|table_id: table_id}, rest) end defp decode_props(pktin, <<@cookie::16, _length::16, _::32, cookie::64, rest::bytes>>) do decode_props(%{pktin|cookie: cookie}, rest) end defp decode_props(pktin, <<@reason::16, _length::16, reason_int::8, _::24, rest::bytes>>) do reason = Openflow.Enums.to_atom(reason_int, :packet_in_reason) decode_props(%{pktin|reason: reason}, rest) end defp decode_props(pktin, <<@metadata::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) match_field_length = length - @prop_header_length <> = tail match_len = 4 + byte_size(match_fields_bin) padding = Openflow.Utils.pad_length(match_len, 8) match_bin = (<<1::16, match_len::16, match_fields_bin::bytes, 0::size(padding)-unit(8)>>) {fields, _rest} = Openflow.Match.read(match_bin) decode_props(%{pktin|metadata: fields}, rest) end defp decode_props(pktin, <<@userdata::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) userdata_length = length - @prop_header_length <> = tail decode_props(%{pktin|userdata: userdata}, rest) end defp decode_props(pktin, <<@continuation::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = length - @prop_header_length - 4 <<_pad::32, data::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail pktin |> decode_continuations(data) |> decode_props(rest) end defp decode_props(pktin, <<_::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = length - @prop_header_length <<_data::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail decode_props(pktin, rest) end defp decode_continuations(pktin, ""), do: pktin defp decode_continuations(pktin, <<@nxcpt_bridge::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = length - @prop_header_length <> = tail decode_continuations(%{pktin|continuation_bridge: bridge}, rest) end defp decode_continuations(pktin, <<@nxcpt_stack::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = (length - @prop_header_length) * 8 <> = tail decode_continuations(%{pktin|continuation_stack: pktin.continuation_stack ++ [stack]}, rest) end defp decode_continuations(pktin, <<@nxcpt_mirrors::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = length - @prop_header_length <> = tail decode_continuations(%{pktin|continuation_mirrors: mirrors}, rest) end defp decode_continuations(pktin, <<@nxcpt_conntracked::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = length - @prop_header_length <<_::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail decode_continuations(%{pktin|continuation_conntracked: true}, rest) end defp decode_continuations(pktin, <<@nxcpt_table_id::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) <> = tail decode_continuations(%{pktin|continuation_table_id: table_id}, rest) end defp decode_continuations(pktin, <<@nxcpt_cookie::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) <> = tail decode_continuations(%{pktin|continuation_cookie: cookie}, rest) end defp decode_continuations(pktin, <<@nxcpt_actions::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = length - @prop_header_length - 4 <<_pad::32, actions::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail decode_continuations(%{pktin|continuation_actions: Openflow.Action.read(actions)}, rest) end defp decode_continuations(pktin, <<@nxcpt_action_set::16, length::16, tail::bytes>>) do pad_length = Openflow.Utils.pad_length(length, 8) data_length = length - @prop_header_length <> = tail decode_continuations(%{pktin|continuation_action_set: action_set}, rest) end defp decode_continuations(pktin, _) do decode_continuations(pktin, "") end end