defmodule Openflow.Multipart.Flow.Reply do defstruct( version: 4, xid: 0, datapath_id: nil, # virtual field aux_id: nil, flags: [], flows: [] ) alias __MODULE__ def ofp_type, do: 18 def new(flows \\ []) do %Reply{flows: flows} end def read(<>) do flows = Openflow.Multipart.FlowStats.read(flows_bin) %Reply{flows: flows} end def append_body(%Reply{flows: flows} = message, %Reply{flags: [:more], flows: continue}) do %{message|flows: [continue|flows]} end def append_body(%Reply{flows: flows} = message, %Reply{flags: [], flows: continue}) do new_flows = [continue|flows] |> Enum.reverse |> List.flatten %{message|flows: new_flows} end end defmodule Openflow.Multipart.FlowStats do defstruct( table_id: 0, duration_sec: 0, duration_nsec: 0, priority: 0, idle_timeout: 0, hard_timeout: 0, flags: 0, cookie: 0, packet_count: 0, byte_count: 0, match: [], instructions: [] ) alias __MODULE__ def read(binary) do do_read([], binary) end # private functions defp do_read(acc, ""), do: Enum.reverse(acc) defp do_read(acc, <> = binary) do <> = binary do_read([codec(flow_stats_bin)|acc], rest) end defp codec(<<_length::16, table_id_int::8, 0::8, duration_sec::32, duration_nsec::32, priority::16, idle::16, hard::16, flags_int::16, _::size(4)-unit(8), cookie::64, packet_count::64, byte_count::64, tail::bytes>>) do {match, instructions_bin} = Openflow.Match.read(tail) table_id = Openflow.Utils.get_enum(table_id_int, :table_id) flags = Openflow.Enums.int_to_flags(flags_int, :flow_mod_flags) instructions = Openflow.Instruction.read(instructions_bin) %FlowStats{table_id: table_id, duration_sec: duration_sec, duration_nsec: duration_nsec, priority: priority, idle_timeout: idle, hard_timeout: hard, flags: flags, cookie: cookie, packet_count: packet_count, byte_count: byte_count, match: match, instructions: instructions} end end