diff --git a/include/ofp_v4.hrl b/include/ofp_v4.hrl index 7ffd119..094cd74 100644 --- a/include/ofp_v4.hrl +++ b/include/ofp_v4.hrl @@ -29,6 +29,7 @@ -define(OFPCML_MAX, 16#ffe5). %% buffer id -define(OFPCML_NO_BUFFER, 16#ffff). %% buffer id -define(OFPM_MAX, 16#ffff0000). %% flow meter number +-define(OFPM_MAX_SIZE,16#10000). %% Max multipart message size %% Message sizes (in bytes) ---------------------------------------------------- diff --git a/include/ofp_v5.hrl b/include/ofp_v5.hrl index 7fc0d0e..a41b2b2 100644 --- a/include/ofp_v5.hrl +++ b/include/ofp_v5.hrl @@ -29,6 +29,7 @@ -define(OFPCML_MAX, 16#ffe5). %% buffer id -define(OFPCML_NO_BUFFER, 16#ffff). %% buffer id -define(OFPM_MAX, 16#ffff0000). %% flow meter number +-define(OFPM_MAX_SIZE,16#10000). %% Max multipart message size %% Message sizes (in bytes) ---------------------------------------------------- @@ -1550,6 +1551,9 @@ %%% Request Forward Message (version 1.4.0, section 7.4.6) %%%----------------------------------------------------------------------------- +-type ofp_requestforward_reason() :: group_mod + | meter_mod. + -record(ofp_requestforward, { request :: ofp_message() }). @@ -1563,25 +1567,50 @@ -type ofp_get_async_request() :: #ofp_get_async_request{}. -record(ofp_get_async_reply, { - packet_in_mask = {[], []} :: {[ofp_packet_in_reason()], - [ofp_packet_in_reason()]}, - port_status_mask = {[], []} :: {[ofp_port_status_reason()], - [ofp_port_status_reason()]}, - flow_removed_mask = {[], []} :: {[ofp_flow_removed_reason()], - [ofp_flow_removed_reason()]} + properties = [] :: [ofp_async_config_property()] }). -type ofp_get_async_reply() :: #ofp_get_async_reply{}. -record(ofp_set_async, { - packet_in_mask = {[], []} :: {[ofp_packet_in_reason()], - [ofp_packet_in_reason()]}, - port_status_mask = {[], []} :: {[ofp_port_status_reason()], - [ofp_port_status_reason()]}, - flow_removed_mask = {[], []} :: {[ofp_flow_removed_reason()], - [ofp_flow_removed_reason()]} + properties = [] :: [ofp_async_config_property()] }). -type ofp_set_async() :: #ofp_set_async{}. +-type ofp_async_config_prop_type() :: packet_in_slave + | packet_in_master + | port_status_slave + | port_status_master + | flow_removed_slave + | flow_removed_master + | role_status_slave + | role_status_master + | table_status_slave + | table_status_master + | requestforward_slave + | requestforward_master + | experimenter_slave + | experimenter_master. + +-record(ofp_async_config_prop_reasons, { + type :: ofp_async_config_prop_type(), + mask = [] :: [ofp_packet_in_reason()] + | [ofp_port_status_reason()] + | [ofp_flow_removed_reason()] + | [ofp_controller_role_reason()] + | [ofp_table_reason()] + | [ofp_requestforward_reason()] + }). + +-record(ofp_async_config_prop_experimenter, { + type :: ofp_async_config_prop_type(), + experimenter :: integer(), + exp_type :: integer(), + data = <<>> :: binary() + }). + +-type ofp_async_config_property() :: #ofp_async_config_prop_reasons{} + | #ofp_async_config_prop_experimenter{}. + %%%----------------------------------------------------------------------------- %%% Bundle Messages (version 1.4.0, section 7.3.9) %%%----------------------------------------------------------------------------- diff --git a/src/ofp_client.erl b/src/ofp_client.erl index 7064951..270ff35 100644 --- a/src/ofp_client.erl +++ b/src/ofp_client.erl @@ -381,12 +381,12 @@ handle_send(#ofp_message{type = packet_in} = Message, _Else -> do_filter_send(Message, State) end; -handle_send(#ofp_message{type = multipart_reply} = Message, - #state{version = Version} = State) -> +handle_send(#ofp_message{type = Type} = Message, + #state{version = Version} = State) when Type =:= multipart_reply -> Module = client_module(Version), Replies = Module:split_multipart(Message), Results = [do_send(Reply, State) || Reply <- Replies], - case lists:all(fun(X) -> X == ok end, Results) of + case lists:all(fun(X) -> X == ok end, lists:flatten(Results) ) of true -> ok; false -> @@ -395,6 +395,27 @@ handle_send(#ofp_message{type = multipart_reply} = Message, handle_send(Message, State) -> do_filter_send(Message, State). +do_send(#ofp_message{ type = Type } = Message, #state{controller = {_, _, Proto}, + socket = Socket, + parser = Parser, + version = Version} = State) when Type =:= multipart_reply -> + case ofp_parser:encode(Parser, Message#ofp_message{version = Version}) of + {ok, Binary} -> + case byte_size(Binary) < (1 bsl 16) of + true -> + send(Proto, Socket, Binary); + false -> + Module = client_module(Version), + case Module:split_big_multipart(Message) of + false -> + {error, message_too_big}; + SplitList -> + lists:map(fun(Msg) -> do_send(Msg,State) end, SplitList) + end + end; + {error, Reason} -> + {error, Reason} + end; do_send(Message, #state{controller = {_, _, Proto}, socket = Socket, parser = Parser, diff --git a/src/ofp_client_v4.erl b/src/ofp_client_v4.erl index 9fd4b70..d4f2e89 100644 --- a/src/ofp_client_v4.erl +++ b/src/ofp_client_v4.erl @@ -27,7 +27,9 @@ filter_out_message/3, type_atom/1, add_aux_id/2, - split_multipart/1]). + split_multipart/1, + split_big_multipart/1 + ]). -include("of_protocol.hrl"). -include("ofp_v4.hrl"). @@ -261,5 +263,95 @@ split2(_, [], Head) -> split2(N, [X | Tail], Head) -> split2(N - 1, Tail, [X | Head]). +%% False inner boddies, cant be split into reliable complete messages. +multipart_inner_body(#ofp_desc_request {} = _Msg) -> false; +multipart_inner_body(#ofp_desc_reply {} = _Msg) -> false; +multipart_inner_body(#ofp_flow_stats_request {} = _Msg) -> false; +multipart_inner_body(#ofp_flow_stats_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_aggregate_stats_request{} = _Msg) -> false; +multipart_inner_body(#ofp_aggregate_stats_reply {} = _Msg) -> false; +multipart_inner_body(#ofp_table_stats_request {} = _Msg) -> false; +multipart_inner_body(#ofp_table_stats_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_table_features_request {} = _Msg) -> false; +multipart_inner_body(#ofp_table_features_reply {} = _Msg) -> false; +multipart_inner_body(#ofp_port_stats_request {} = _Msg) -> false; +multipart_inner_body(#ofp_port_stats_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_port_desc_request {} = _Msg) -> false; +multipart_inner_body(#ofp_port_desc_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_queue_stats_request {} = _Msg) -> false; +multipart_inner_body(#ofp_queue_stats_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_group_stats_request {} = _Msg) -> false; +multipart_inner_body(#ofp_group_stats_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_group_desc_request {} = _Msg) -> false; +multipart_inner_body(#ofp_group_desc_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_group_features_request {} = _Msg) -> false; +multipart_inner_body(#ofp_group_features_reply {} = _Msg) -> false; +multipart_inner_body(#ofp_meter_stats_request {} = _Msg) -> false; +multipart_inner_body(#ofp_meter_stats_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_meter_config_request {} = _Msg) -> false; +multipart_inner_body(#ofp_meter_config_reply { body = InnerBody } = _Msg)-> {body,InnerBody}; +multipart_inner_body(#ofp_meter_features_request {} = _Msg) -> false; +multipart_inner_body(#ofp_meter_features_reply {} = _Msg) -> false; +multipart_inner_body(#ofp_experimenter_request {} = _Msg) -> false; +multipart_inner_body(#ofp_experimenter_reply {} = _Msg) -> false. + +remove_inner_body(#ofp_flow_stats_reply {} = Body) -> Body#ofp_flow_stats_reply { body = [] }; +remove_inner_body(#ofp_table_stats_reply {} = Body) -> Body#ofp_table_stats_reply { body = [] }; +remove_inner_body(#ofp_port_stats_reply {} = Body) -> Body#ofp_port_stats_reply { body = [] }; +remove_inner_body(#ofp_port_desc_reply {} = Body) -> Body#ofp_port_desc_reply { body = [] }; +remove_inner_body(#ofp_queue_stats_reply {} = Body) -> Body#ofp_queue_stats_reply { body = [] }; +remove_inner_body(#ofp_group_stats_reply {} = Body) -> Body#ofp_group_stats_reply { body = [] }; +remove_inner_body(#ofp_group_desc_reply {} = Body) -> Body#ofp_group_desc_reply { body = [] }; +remove_inner_body(#ofp_meter_stats_reply {} = Body) -> Body#ofp_meter_stats_reply { body = [] }; +remove_inner_body(#ofp_meter_config_reply {} = Body) -> Body#ofp_meter_config_reply { body = [] }. + +reasemble_inner_body(#ofp_flow_stats_reply {} = Body,InnerBody) -> Body#ofp_flow_stats_reply { body = InnerBody }; +reasemble_inner_body(#ofp_table_stats_reply {} = Body,InnerBody) -> Body#ofp_table_stats_reply { body = InnerBody }; +reasemble_inner_body(#ofp_port_stats_reply {} = Body,InnerBody) -> Body#ofp_port_stats_reply { body = InnerBody }; +reasemble_inner_body(#ofp_port_desc_reply {} = Body,InnerBody) -> Body#ofp_port_desc_reply { body = InnerBody }; +reasemble_inner_body(#ofp_queue_stats_reply {} = Body,InnerBody) -> Body#ofp_queue_stats_reply { body = InnerBody }; +reasemble_inner_body(#ofp_group_stats_reply {} = Body,InnerBody) -> Body#ofp_group_stats_reply { body = InnerBody }; +reasemble_inner_body(#ofp_group_desc_reply {} = Body,InnerBody) -> Body#ofp_group_desc_reply { body = InnerBody }; +reasemble_inner_body(#ofp_meter_stats_reply {} = Body,InnerBody) -> Body#ofp_meter_stats_reply { body = InnerBody }; +reasemble_inner_body(#ofp_meter_config_reply {} = Body,InnerBody) -> Body#ofp_meter_config_reply { body = InnerBody }. + +%% SPLIT THE MESSAGE INTO 2 bits, the Body and the rest, +%% Encode and parse the REST, and use that size as the +%% Deduction for the maximum size.... ( - 16 ) + +split_big_multipart(#ofp_message{type = _Type, version = V, body = Body} = Message) -> + case multipart_inner_body(Body) of + false -> + false; + {body,InnerBody} -> + SkeletonBody = Message#ofp_message{ body = remove_inner_body(Body) }, + [ Message#ofp_message{body = reasemble_inner_body(Body,Chunk) } || + Chunk <- split_big_multipart_structs(SkeletonBody,InnerBody,[],V) ] + end. + +split_big_multipart_structs(SkeletonBody,Body,Chunks,Version) -> + Module = encode_module(Version), + case split_structs_chunks(Body,[],0,Module) of + {ok,{[],Chunk}} -> [Chunk|Chunks]; + {ok,{Rest,Chunk}} -> split_big_multipart_structs(SkeletonBody,Rest,[Chunk|Chunks],Version) + end. + +split_structs_chunks([],Results,_TotalSize,_Module) -> + {ok,{[],Results}}; +split_structs_chunks([H|T],Results,TotalSize,Module) -> + Bin = Module:encode_struct(H), + NewTotalSize = byte_size(Bin) + TotalSize, + case NewTotalSize < ( ?OFPM_MAX_SIZE - 16 ) of %% 16 bytes for the ofp_message bin encasing the actual multipart message etc + true -> split_structs_chunks(T,[H|Results],NewTotalSize,Module); + false -> {ok,{[H|T],Results}} + end. + +encode_module(3) -> + ofp_v3_encode; +encode_module(4) -> + ofp_v4_encode; +encode_module(5) -> + ofp_v5_encode. + should_filter_out(Reason, Filter) -> - not lists:member(Reason, Filter). + not lists:member(Reason, Filter). \ No newline at end of file diff --git a/src/ofp_client_v5.erl b/src/ofp_client_v5.erl index a0d4a38..b0b1488 100644 --- a/src/ofp_client_v5.erl +++ b/src/ofp_client_v5.erl @@ -23,12 +23,12 @@ create_role/2, extract_role/1, role_status/3, - create_async/1, - extract_async/1, filter_out_message/3, type_atom/1, add_aux_id/2, - split_multipart/1]). + split_multipart/1, + split_big_multipart/1 + ]). -include("of_protocol.hrl"). -include("ofp_v5.hrl"). @@ -59,36 +59,6 @@ role_status(Role, Reason, GenId) -> reason = Reason, generation_id = GenId}. -%% @doc Create async filters message. --spec create_async(#async_config{}) -> #ofp_get_async_reply{}. -create_async(#async_config{ - master_equal_packet_in = MEP, - master_equal_port_status = MES, - master_equal_flow_removed = MEF, - slave_packet_in = SP, - slave_port_status = SS, - slave_flow_removed = SF}) -> - %% Ensure that we don't try to send v4 values - MEP5 = MEP -- [no_match, action], - SP5 = SP -- [no_match, action], - #ofp_get_async_reply{packet_in_mask = {MEP5, SP5}, - port_status_mask = {MES, SS}, - flow_removed_mask = {MEF, SF}}. - -%% @doc Extract async filters information. --spec extract_async(#ofp_set_async{}) -> #async_config{}. -extract_async(#ofp_set_async{packet_in_mask = {MEP, SP}, - port_status_mask = {MES, SS}, - flow_removed_mask = {MEF, SF}}) -> - #async_config{ - master_equal_packet_in = MEP, - master_equal_port_status = MES, - master_equal_flow_removed = MEF, - slave_packet_in = SP, - slave_port_status = SS, - slave_flow_removed = SF - }. - -spec filter_out_message(#ofp_message{}, master | slave | equal, #async_config{}) -> boolean(). @@ -278,5 +248,43 @@ split2(_, [], Head) -> split2(N, [X | Tail], Head) -> split2(N - 1, Tail, [X | Head]). + +split_big_multipart(#ofp_message{ version = Version, + body = #ofp_port_stats_reply{body = MultipartReplyBody} + } = Message) -> + Chunks = split_big_multipart_structs(MultipartReplyBody,[],Version), + [ Message#ofp_message{body = #ofp_port_stats_reply{body = Chunk} } || Chunk <- Chunks ]; +split_big_multipart(#ofp_message{ version = _Version, + body = _Body + } = Message) -> + [Message]. + +split_big_multipart_structs(Body,Chunks,Version) -> + Module = encode_module(Version), + case split_structs_chunks(Body,[],0,Module) of + {ok,{[],Chunk}} -> + [Chunk|Chunks]; + {ok,{Rest,Chunk}} -> + split_big_multipart_structs(Rest,[Chunk|Chunks],Version) + end. + +split_structs_chunks([],Results,_TotalSize,_Module) -> + {ok,{[],Results}}; +split_structs_chunks([H|T],Results,TotalSize,Module) -> + Bin = Module:encode_struct(H), + NewTotalSize = byte_size(Bin) + TotalSize, + case NewTotalSize < ( ?OFPM_MAX_SIZE - 8 ) of + true -> split_structs_chunks(T,[H|Results],NewTotalSize,Module); + false -> {ok,{[H|T],Results}} %% Give back REST ( Remainder=[H|T] ) as starting point, for next itteration. + end. + +encode_module(3) -> + ofp_v3_encode; +encode_module(4) -> + ofp_v4_encode; +encode_module(5) -> + ofp_v5_encode. + + should_filter_out(Reason, Filter) -> not lists:member(Reason, Filter). diff --git a/src/ofp_v4_encode.erl b/src/ofp_v4_encode.erl index 679cde1..6b59520 100644 --- a/src/ofp_v4_encode.erl +++ b/src/ofp_v4_encode.erl @@ -22,7 +22,8 @@ %% @private -module(ofp_v4_encode). --export([do/1]). +-export([do/1, + encode_struct/1]). -include("of_protocol.hrl"). -include("ofp_v4.hrl"). diff --git a/src/ofp_v5_decode.erl b/src/ofp_v5_decode.erl index bbdb8ea..0ab403f 100644 --- a/src/ofp_v5_decode.erl +++ b/src/ofp_v5_decode.erl @@ -210,21 +210,64 @@ decode_properties(Binary, Properties) -> end, decode_properties(Rest, [Property | Properties]). -%% @doc Decode bitmasks in async messages. -decode_async_masks(<>) -> - PacketInMask1 = binary_to_flags(packet_in_reason, PacketInMaskBin1), - PacketInMask2 = binary_to_flags(packet_in_reason, PacketInMaskBin2), - PortStatusMask1 = binary_to_flags(port_reason, PortReasonMaskBin1), - PortStatusMask2 = binary_to_flags(port_reason, PortReasonMaskBin2), - FlowRemovedMask1 = binary_to_flags(flow_removed_reason, - FlowRemovedMaskBin1), - FlowRemovedMask2 = binary_to_flags(flow_removed_reason, - FlowRemovedMaskBin2), - {{PacketInMask1, PacketInMask2}, - {PortStatusMask1, PortStatusMask2}, - {FlowRemovedMask1, FlowRemovedMask2}}. +decode_async_config_properties(<<>>) -> + []; +decode_async_config_properties(<>) -> + Type = ofp_v5_enum:to_atom(async_config_prop_type, TypeInt), + RemainingLength = Length - 4, + PaddingLength = (Length + 7) div 8 * 8 - Length, + <> = Rest, + [decode_async_config_property(Type, PropBin) | + decode_async_config_properties(Tail)]. + +decode_async_config_property(packet_in_slave, <>) -> + Mask = binary_to_flags(packet_in_reason, MaskBin), + #ofp_async_config_prop_reasons{type = packet_in_slave, mask = Mask}; +decode_async_config_property(packet_in_master, <>) -> + Mask = binary_to_flags(packet_in_reason, MaskBin), + #ofp_async_config_prop_reasons{type = packet_in_master, mask = Mask}; +decode_async_config_property(port_status_slave, <>) -> + Mask = binary_to_flags(port_reason, MaskBin), + #ofp_async_config_prop_reasons{type = port_status_slave, mask = Mask}; +decode_async_config_property(port_status_master, <>) -> + Mask = binary_to_flags(port_reason, MaskBin), + #ofp_async_config_prop_reasons{type = port_status_master, mask = Mask}; +decode_async_config_property(flow_removed_slave, <>) -> + Mask = binary_to_flags(flow_removed_reason, MaskBin), + #ofp_async_config_prop_reasons{type = flow_removed_slave, mask = Mask}; +decode_async_config_property(flow_removed_master, <>) -> + Mask = binary_to_flags(flow_removed_reason, MaskBin), + #ofp_async_config_prop_reasons{type = flow_removed_master, mask = Mask}; +decode_async_config_property(role_status_slave, <>) -> + Mask = binary_to_flags(controller_role_reason, MaskBin), + #ofp_async_config_prop_reasons{type = role_status_slave, mask = Mask}; +decode_async_config_property(role_status_master, <>) -> + Mask = binary_to_flags(controller_role_reason, MaskBin), + #ofp_async_config_prop_reasons{type = role_status_master, mask = Mask}; +decode_async_config_property(table_status_slave, <>) -> + Mask = binary_to_flags(table_reason, MaskBin), + #ofp_async_config_prop_reasons{type = table_status_slave, mask = Mask}; +decode_async_config_property(table_status_master, <>) -> + Mask = binary_to_flags(table_reason, MaskBin), + #ofp_async_config_prop_reasons{type = table_status_master, mask = Mask}; +decode_async_config_property(requestforward_slave, <>) -> + Mask = binary_to_flags(requestforward_reason, MaskBin), + #ofp_async_config_prop_reasons{type = requestforward_slave, mask = Mask}; +decode_async_config_property(requestforward_master, <>) -> + Mask = binary_to_flags(requestforward_reason, MaskBin), + #ofp_async_config_prop_reasons{type = requestforward_master, mask = Mask}; +decode_async_config_property(experimenter_slave, + <>) -> + #ofp_async_config_prop_experimenter{type = experimenter_slave, + experimenter = Experimenter, + exp_type = ExpType, + data = Data}; +decode_async_config_property(experimenter_master, + <>) -> + #ofp_async_config_prop_experimenter{type = experimenter_master, + experimenter = Experimenter, + exp_type = ExpType, + data = Data}. %% @doc Decode meter mod bands decode_bands(Binary) -> @@ -1367,15 +1410,9 @@ decode_body(requestforward, Binary) -> decode_body(get_async_request, _) -> #ofp_get_async_request{}; decode_body(get_async_reply, Binary) -> - {PacketInMask, PortStatusMask, FlowRemovedMask} = decode_async_masks(Binary), - #ofp_get_async_reply{packet_in_mask = PacketInMask, - port_status_mask = PortStatusMask, - flow_removed_mask = FlowRemovedMask}; + #ofp_get_async_reply{properties = decode_async_config_properties(Binary)}; decode_body(set_async, Binary) -> - {PacketInMask, PortStatusMask, FlowRemovedMask} = decode_async_masks(Binary), - #ofp_set_async{packet_in_mask = PacketInMask, - port_status_mask = PortStatusMask, - flow_removed_mask = FlowRemovedMask}; + #ofp_set_async{properties = decode_async_config_properties(Binary)}; decode_body(meter_mod, Binary) -> <> = Binary, Command = get_id(meter_mod_command, CommandInt), diff --git a/src/ofp_v5_encode.erl b/src/ofp_v5_encode.erl index b9cc5d3..ce2cc79 100644 --- a/src/ofp_v5_encode.erl +++ b/src/ofp_v5_encode.erl @@ -22,7 +22,9 @@ %% @private -module(ofp_v5_encode). --export([do/1]). +-export([do/1, + encode_struct/1 + ]). -include("of_protocol.hrl"). -include("ofp_v5.hrl"). @@ -484,6 +486,46 @@ encode_struct(#ofp_flow_update_abbrev{event = Event, encode_struct(#ofp_flow_update_paused{event = Event}) -> EventInt = ofp_v5_enum:to_int(flow_update_event, Event), <<8:16, EventInt:16, 0:32>>; +encode_struct(#ofp_async_config_prop_reasons{type = Type, mask = Mask}) -> + TypeInt = ofp_v5_enum:to_int(async_config_prop_type, Type), + case Type of + packet_in_slave -> + MaskInt = flags_to_binary(packet_in_reason, Mask, 4); + packet_in_master -> + MaskInt = flags_to_binary(packet_in_reason, Mask, 4); + port_status_slave -> + MaskInt = flags_to_binary(port_reason, Mask, 4); + port_status_master -> + MaskInt = flags_to_binary(port_reason, Mask, 4); + flow_removed_slave -> + MaskInt = flags_to_binary(flow_removed_reason, Mask, 4); + flow_removed_master -> + MaskInt = flags_to_binary(flow_removed_reason, Mask, 4); + role_status_slave -> + MaskInt = flags_to_binary(controller_role_reason, Mask, 4); + role_status_master -> + MaskInt = flags_to_binary(controller_role_reason, Mask, 4); + table_status_slave -> + MaskInt = flags_to_binary(table_reason, Mask, 4); + table_status_master -> + MaskInt = flags_to_binary(table_reason, Mask, 4); + requestforward_slave -> + MaskInt = flags_to_binary(requestforward_reason, Mask, 4); + requestforward_master -> + MaskInt = flags_to_binary(requestforward_reason, Mask, 4) + end, + Length = 8, + <>; +encode_struct(#ofp_async_config_prop_experimenter{ + type = Type, + experimenter = Experimenter, + exp_type = ExpType, + data = Data}) -> + TypeInt = ofp_v5_enum:to_int(async_config_prop_type, Type), + Length = 12 + byte_size(Data), + Padding = ofp_utils:padding(Length, 8) * 8, + <>; encode_struct(#ofp_bundle_prop_experimenter{ experimenter = Experimenter, exp_type = ExpType, @@ -494,19 +536,6 @@ encode_struct(#ofp_bundle_prop_experimenter{ ExpType:32, Data/binary>>). - -encode_async_masks({PacketInMask1, PacketInMask2}, - {PortStatusMask1, PortStatusMask2}, - {FlowRemovedMask1, FlowRemovedMask2}) -> - PIn1 = flags_to_binary(packet_in_reason, PacketInMask1, 4), - PIn2 = flags_to_binary(packet_in_reason, PacketInMask2, 4), - PS1 = flags_to_binary(port_reason, PortStatusMask1, 4), - PS2 = flags_to_binary(port_reason, PortStatusMask2, 4), - FR1 = flags_to_binary(flow_removed_reason, FlowRemovedMask1, 4), - FR2 = flags_to_binary(flow_removed_reason, FlowRemovedMask2, 4), - <>. - encode_bitmap([], Size, Acc) -> Bytes = (Size + 1) * 32, <>; @@ -940,14 +969,10 @@ encode_body(#ofp_requestforward{request = Request}) -> do(Request); encode_body(#ofp_get_async_request{}) -> <<>>; -encode_body(#ofp_get_async_reply{packet_in_mask = PacketInMask, - port_status_mask = PortStatusMask, - flow_removed_mask = FlowRemovedMask}) -> - encode_async_masks(PacketInMask, PortStatusMask, FlowRemovedMask); -encode_body(#ofp_set_async{packet_in_mask = PacketInMask, - port_status_mask = PortStatusMask, - flow_removed_mask = FlowRemovedMask}) -> - encode_async_masks(PacketInMask, PortStatusMask, FlowRemovedMask); +encode_body(#ofp_get_async_reply{properties = Properties}) -> + list_to_binary(lists:map(fun encode_struct/1, Properties)); +encode_body(#ofp_set_async{properties = Properties}) -> + list_to_binary(lists:map(fun encode_struct/1, Properties)); encode_body(#ofp_meter_mod{command = Command, flags = Flags, meter_id = MeterId, diff --git a/src/ofp_v5_enum.erl b/src/ofp_v5_enum.erl index 42f33a7..1daba92 100644 --- a/src/ofp_v5_enum.erl +++ b/src/ofp_v5_enum.erl @@ -136,6 +136,23 @@ max_rate, {experimenter, 16#ffff}]}). +%% Acync Config Structures ----------------------------------------------------- + +-enum({async_config_prop_type, [packet_in_slave, + packet_in_master, + port_status_slave, + port_status_master, + flow_removed_slave, + flow_removed_master, + role_status_slave, + role_status_master, + table_status_slave, + table_status_master, + requestforward_slave, + requestforward_master, + {experimenter_slave, 16#fffe}, + {experimenter_master, 16#ffff}]}). + %% Flow Match Structures ------------------------------------------------------- -enum({match_type, [standard, @@ -436,6 +453,11 @@ -enum({table_reason, [{vacancy_down, 3}, {vacancy_up, 4}]}). +%% Request Forward Messages ---------------------------------------------------- + +-enum({requestforward_reason, [group_mod, + meter_mod]}). + %% Bundle Messages ------------------------------------------------------------- -enum({bundle_ctrl_type, [open_request,