From 8344ff117febf11c2962610e7318eece8211f771 Mon Sep 17 00:00:00 2001 From: "ruan800@gmail.com" Date: Fri, 7 Mar 2014 12:20:19 +0000 Subject: [PATCH 1/4] completed multipart splitting. --- include/ofp_v4.hrl | 1 + include/ofp_v5.hrl | 1 + src/ofp_client.erl | 27 ++++++++++-- src/ofp_client_v4.erl | 96 ++++++++++++++++++++++++++++++++++++++++++- src/ofp_client_v5.erl | 42 ++++++++++++++++++- src/ofp_v4_encode.erl | 3 +- src/ofp_v5_encode.erl | 4 +- 7 files changed, 166 insertions(+), 8 deletions(-) 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 c6230a8..7298c2f 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) ---------------------------------------------------- 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..6f76bf9 100644 --- a/src/ofp_client_v5.erl +++ b/src/ofp_client_v5.erl @@ -28,7 +28,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_v5.hrl"). @@ -278,5 +280,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_encode.erl b/src/ofp_v5_encode.erl index 54428b3..c6c3c24 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"). From 548d62ce32c3395ac6f9c2da41b0553da5e458c0 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 6 Mar 2014 16:40:07 +0900 Subject: [PATCH 2/4] Add ofp_requestforward_reason This will be used when encoding and decoding masks for set async and get async reply properties. Signed-off-by: Simon Horman --- include/ofp_v5.hrl | 3 +++ src/ofp_v5_enum.erl | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/include/ofp_v5.hrl b/include/ofp_v5.hrl index 3e300a2..f32ca98 100644 --- a/include/ofp_v5.hrl +++ b/include/ofp_v5.hrl @@ -1551,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() }). diff --git a/src/ofp_v5_enum.erl b/src/ofp_v5_enum.erl index 42f33a7..179233b 100644 --- a/src/ofp_v5_enum.erl +++ b/src/ofp_v5_enum.erl @@ -436,6 +436,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, From d383435fe87b7a198bf75bddcf31d63638d5b6f6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 6 Mar 2014 16:40:07 +0900 Subject: [PATCH 3/4] Add ofp_async_config_prop_{reasons,experimenter} This will be used when encoding and decoding set async and get async reply properties. Signed-off-by: Simon Horman --- include/ofp_v5.hrl | 35 +++++++++++++++++++++++++++++++++++ src/ofp_v5_enum.erl | 17 +++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/include/ofp_v5.hrl b/include/ofp_v5.hrl index f32ca98..fe331fc 100644 --- a/include/ofp_v5.hrl +++ b/include/ofp_v5.hrl @@ -1586,6 +1586,41 @@ }). -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_v5_enum.erl b/src/ofp_v5_enum.erl index 179233b..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, From 4b8e0a14d6c4c5148ac3006cdd261e56d5b8c38b Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Sun, 2 Mar 2014 15:38:01 +0900 Subject: [PATCH 4/4] Update get async reply and set async for protocol v5 The current implementation of get async reply and set async for protocol v5 is follows that of protocol v4. However, the OpenFlow 1.4.0 specification defines a rather different format. This patch updates the implementation to follow the specification. Signed-off-by: Simon Horman --- include/ofp_v5.hrl | 14 ++------ src/ofp_client_v5.erl | 32 ----------------- src/ofp_v5_decode.erl | 83 +++++++++++++++++++++++++++++++------------ src/ofp_v5_encode.erl | 65 ++++++++++++++++++++++----------- 4 files changed, 106 insertions(+), 88 deletions(-) diff --git a/include/ofp_v5.hrl b/include/ofp_v5.hrl index fe331fc..a41b2b2 100644 --- a/include/ofp_v5.hrl +++ b/include/ofp_v5.hrl @@ -1567,22 +1567,12 @@ -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{}. diff --git a/src/ofp_client_v5.erl b/src/ofp_client_v5.erl index 6f76bf9..b0b1488 100644 --- a/src/ofp_client_v5.erl +++ b/src/ofp_client_v5.erl @@ -23,8 +23,6 @@ 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, @@ -61,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(). 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 8d38233..ce2cc79 100644 --- a/src/ofp_v5_encode.erl +++ b/src/ofp_v5_encode.erl @@ -486,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, @@ -496,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, <>; @@ -942,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,