From 2df9af2b555eaf57fd196580cb828933368b77aa Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Wed, 20 Nov 2013 11:49:55 +0900 Subject: [PATCH 1/4] add experimeter_id enum probably this should not be v4 specific. --- src/ofp_v4_enum.erl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ofp_v4_enum.erl b/src/ofp_v4_enum.erl index 34418cb..daada6f 100644 --- a/src/ofp_v4_enum.erl +++ b/src/ofp_v4_enum.erl @@ -109,6 +109,11 @@ pause, pause_asym]}). +-enum({experimeter_id, [{nx, 16#00002300}, %% Nicira + {bsn, 16#005c16c7}, %% Big Switch Networks + {onf, 16#4f4e4600}]}). %% OpenFlow Extensions for + %% 1.3.X Pack 1 + %% Queue Structures ------------------------------------------------------------ %% Note: Not in the specification From 161c7d2db2479c553e154c541bdfa6bbddf45941 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Wed, 20 Nov 2013 12:02:28 +0900 Subject: [PATCH 2/4] implement OF1.3 EXT-256 (PBB UCA match field) --- include/ofp_v4.hrl | 8 ++++++-- src/ofp_v4_decode.erl | 31 +++++++++++++++++++++++-------- src/ofp_v4_encode.erl | 37 +++++++++++++++++++++++++++++++------ src/ofp_v4_enum.erl | 10 ++++++---- src/ofp_v4_map.erl | 3 ++- 5 files changed, 68 insertions(+), 21 deletions(-) diff --git a/include/ofp_v4.hrl b/include/ofp_v4.hrl index 7ffd119..4cc7761 100644 --- a/include/ofp_v4.hrl +++ b/include/ofp_v4.hrl @@ -289,10 +289,12 @@ %% OXM classes (A 2.3.3) ------------------------------------------------------- +-type experimenter() :: atom(). + -type ofp_field_class() :: nxm_0 | nxm_1 | openflow_basic - | experimenter. + | {experimenter, experimenter()}. %% Flow Match Fields (A 2.3.7) ------------------------------------------------- @@ -337,7 +339,9 @@ | tunnel_id | ipv6_exthdr. --type ofp_field_type() :: openflow_basic_type(). +-type onf_experimenter_type() :: pbb_uca. %% EXT-256 + +-type ofp_field_type() :: openflow_basic_type() | onf_experimenter_type(). -type ofp_vlan_id() :: present | none. diff --git a/src/ofp_v4_decode.erl b/src/ofp_v4_decode.erl index 631a3f7..75e23ff 100644 --- a/src/ofp_v4_decode.erl +++ b/src/ofp_v4_decode.erl @@ -82,25 +82,40 @@ decode_match_field(<>) -> Length:8>> = Header, Class = ofp_v4_enum:to_atom(oxm_class, ClassInt), HasMask = (HasMaskInt =:= 1), - {Field, BitLength} = case Class of + {Class2, Field, BitLength, ByteLength, Binary2} = case Class of openflow_basic -> F = ofp_v4_enum:to_atom(oxm_ofb_match_fields, FieldInt), - {F, ofp_v4_map:tlv_length(F)}; + {Class, F, ofp_v4_map:tlv_length(F), Length, Binary}; + experimenter -> + <> = Binary, + Exp = get_id(experimenter_id, ExpInt), + case Exp of + onf -> + %% EXT-256 + %% see the comment in encode_struct/1 for the weirdness + <> = Binary3, + F = get_id(oxm_onf_match_fields, ExpTypeInt), + %% reduce length for: + %% uint32_t experimenter; + %% uint16_t exp_type; + {{Class, Exp}, + F, ofp_v4_map:tlv_length(F), Length - 6, Binary4} + end; _ -> - {FieldInt, Length * 8} + {Class, FieldInt, Length * 8, Length, Binary} end, case HasMask of false -> - <> = Binary, + <> = Binary2, TLV = #ofp_field{value = ofp_utils:uncut_bits(Value, BitLength)}; true -> - Length2 = (Length div 2), - <> = Binary, + ByteLength2 = (ByteLength div 2), + <> = Binary2, TLV = #ofp_field{value = ofp_utils:uncut_bits(Value, BitLength), mask = ofp_utils:uncut_bits(Mask, BitLength)} end, - {TLV#ofp_field{class = Class, + {TLV#ofp_field{class = Class2, name = Field, has_mask = HasMask}, Rest}. diff --git a/src/ofp_v4_encode.erl b/src/ofp_v4_encode.erl index c231c82..e1de5df 100644 --- a/src/ofp_v4_encode.erl +++ b/src/ofp_v4_encode.erl @@ -53,12 +53,26 @@ encode_struct(#ofp_match{fields = Fields}) -> <<1:16, Length:16, FieldsBin/bytes, 0:Padding>>; encode_struct(#ofp_field{class = Class, name = Field, has_mask = HasMask, value = Value, mask = Mask}) -> - ClassInt = ofp_v4_enum:to_int(oxm_class, Class), + ClassInt = case Class of + {C, _} -> + ofp_v4_enum:to_int(oxm_class, C); + C -> + ofp_v4_enum:to_int(oxm_class, C) + end, {FieldInt, BitLength, WireBitLength} = case Class of openflow_basic -> {ofp_v4_enum:to_int(oxm_ofb_match_fields, Field), ofp_v4_map:tlv_length(Field), ofp_v4_map:tlv_wire_length(Field)}; + {experimenter, onf} -> + %% EXT-256 + %% the definition of onf_oxm_pbb_uca is a bit weird. + %% instead of oxm_field, an additional field "exp_type" is + %% used to specify the field type. it's unclear what value + %% oxm_field should be. + {0, + ofp_v4_map:tlv_length(Field), + ofp_v4_map:tlv_wire_length(Field)}; _ -> Len = bit_size(Value), {Field, Len, Len} @@ -69,14 +83,25 @@ encode_struct(#ofp_field{class = Class, name = Field, has_mask = HasMask, true -> HasMaskInt = 1, Mask2 = ofp_utils:cut_bits(Mask, BitLength, WireBitLength2), - Rest = <>, - Len2 = byte_size(Value2) * 2; + Rest = <>; false -> HasMaskInt = 0, - Rest = <>, - Len2 = byte_size(Value2) + Rest = <> + end, + Rest2 = case Class of + {experimenter, Exp} -> + ExpId = get_id(experimenter_id, Exp), + Rest3 = case Exp of + onf -> + ExpTypeInt = get_id(oxm_onf_match_fields, Field), + <> + end, + <>; + _ -> + Rest end, - <>; + Len2 = byte_size(Rest2), + <>; encode_struct(#ofp_port{port_no = PortNo, hw_addr = HWAddr, name = Name, config = Config, state = State, curr = Curr, diff --git a/src/ofp_v4_enum.erl b/src/ofp_v4_enum.erl index daada6f..1f8df10 100644 --- a/src/ofp_v4_enum.erl +++ b/src/ofp_v4_enum.erl @@ -109,10 +109,10 @@ pause, pause_asym]}). --enum({experimeter_id, [{nx, 16#00002300}, %% Nicira - {bsn, 16#005c16c7}, %% Big Switch Networks - {onf, 16#4f4e4600}]}). %% OpenFlow Extensions for - %% 1.3.X Pack 1 +-enum({experimenter_id, [{nx, 16#00002300}, %% Nicira + {bsn, 16#005c16c7}, %% Big Switch Networks + {onf, 16#4f4e4600}]}). %% OpenFlow Extensions for + %% 1.3.X Pack 1 %% Queue Structures ------------------------------------------------------------ @@ -174,6 +174,8 @@ tunnel_id, ipv6_exthdr]}). +-enum({oxm_onf_match_fields, [{pbb_uca, 2560}]}). %% EXT-256 + -enum({vlan_id, [none, {present, 16#1000}]}). diff --git a/src/ofp_v4_map.erl b/src/ofp_v4_map.erl index 37f2199..bbcfcb4 100644 --- a/src/ofp_v4_map.erl +++ b/src/ofp_v4_map.erl @@ -70,7 +70,8 @@ tlv_length(mpls_tc) -> 3; tlv_length(mpls_bos) -> 1; tlv_length(pbb_isid) -> 24; tlv_length(tunnel_id) -> 64; -tlv_length(ipv6_exthdr) -> 9. +tlv_length(ipv6_exthdr) -> 9; +tlv_length(pbb_uca) -> 1. %% EXT-256 %% @doc Get field's on-wire length in bits. %% From 13136a1f200c0686bd5c8c0131035faa8bc37b74 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 22 Nov 2013 11:32:36 +0900 Subject: [PATCH 3/4] pbb_uca requires ethertype 88e7 --- src/ofp_v4_utils.erl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ofp_v4_utils.erl b/src/ofp_v4_utils.erl index 827ada7..947d13e 100644 --- a/src/ofp_v4_utils.erl +++ b/src/ofp_v4_utils.erl @@ -195,6 +195,8 @@ required(pbb_isid) -> {eth_type,<<16#88E7:16>>}; required(ipv6_exthdr) -> {eth_type,<<16#86dd:16>>}; +required(pbb_uca) -> + {eth_type,<<16#88E7:16>>}; required(_) -> none. @@ -467,6 +469,7 @@ mpls_bos(Val) -> % eth_type=0x88e7 %% pbb_isid +%% pbb_uca %% tunnel_id From 624e1bd1b22d9ea32dda7f251c87fab462d3f763 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 26 Nov 2013 12:35:00 +0900 Subject: [PATCH 4/4] implement onf_flow_monitor_request (OF1.3 EXT-187) --- include/ofp_v4.hrl | 61 +++++++++++++++++++++++++++++++++++++++++++ src/ofp_v4_decode.erl | 43 +++++++++++++++++++++++++++--- src/ofp_v4_encode.erl | 34 +++++++++++++++++++++--- src/ofp_v4_enum.erl | 17 ++++++++++++ 4 files changed, 148 insertions(+), 7 deletions(-) diff --git a/include/ofp_v4.hrl b/include/ofp_v4.hrl index 4cc7761..dd7cfd9 100644 --- a/include/ofp_v4.hrl +++ b/include/ofp_v4.hrl @@ -1567,3 +1567,64 @@ data = <<>> :: binary() }). -type ofp_experimenter() :: #ofp_experimenter{}. + + +%%%----------------------------------------------------------------------------- +%%% ONF Experimenter +%%%----------------------------------------------------------------------------- +%%% EXT-187 + +%% ONFMP_FLOW_MONITOR request + +-type onf_flow_monitor_flags() :: initial + | add + | delete + | modify + | actions + | own. + +-record(onf_flow_monitor, { + id :: integer(), + flags = [] :: onf_flow_monitor_flags(), + out_port = any :: ofp_port_no(), + table_id = all :: ofp_table_id(), + fields = [] :: [ofp_field()] + }). + +-type onf_flow_monitor() :: #onf_flow_monitor{}. + +-record(onf_flow_monitor_request, { + flags = [] :: [ofp_multipart_request_flag()], + body = [] :: [onf_flow_monitor()] + }). + +%% ONFMP_FLOW_MONITOR reply + +-type onf_flow_update_event() :: added + | deleted + | modified + | abbrev. + +-record(onf_flow_update_full, { + event :: onf_flow_update_event(), + reason :: ofp_flow_removed_reason(), + priority = 0 :: integer(), + idle_timeout = 0 :: integer(), + hard_timeout = 0 :: integer(), + table_id = all :: ofp_table_id(), + cookie = <<0:64>> :: binary(), + fields = [] :: [ofp_field()], + instructions = [] :: [ofp_instruction()] + }). + +-record(onf_flow_update_abbrev, { + xid :: integer() + }). + +-type onf_flow_update() :: #onf_flow_update_full{} + | #onf_flow_update_abbrev{}. + +-record(onf_flow_update, { + flags = [] :: [ofp_multipart_reply_flag()], + body = [] :: [onf_flow_update()] + }). diff --git a/src/ofp_v4_decode.erl b/src/ofp_v4_decode.erl index 75e23ff..4394cd0 100644 --- a/src/ofp_v4_decode.erl +++ b/src/ofp_v4_decode.erl @@ -812,6 +812,27 @@ decode_meter_config_list(Binary, MeterConfigs) -> bands = Bands}, decode_meter_config_list(Rest2, [MeterConfig | MeterConfigs]). +decode_flow_monitor(Binary) -> + decode_flow_monitor(Binary, []). + +decode_flow_monitor(<<>>, Acc) -> + lists:reverse(Acc); +decode_flow_monitor(<>, Acc) -> + Flags = binary_to_flags(onf_flow_monitor_flags, FlagsBin), + OutPort = get_id(port_no, OutPortInt), + TableId = get_id(table, TableIdInt), + PadBits = ofp_utils:padding(MatchLen, 8) * 8, + <> = Rest, + Fields = decode_match_fields(FieldsBin), + Rec = #onf_flow_monitor{id = Id, + flags = Flags, + out_port = OutPort, + table_id = TableId, + fields = Fields}, + decode_flow_monitor(Rest2, [Rec | Acc]). + decode_bitmap(_, Index, _, Acc) when Index >= 32 -> Acc; decode_bitmap(Int, Index, Base, Acc) when Int band (1 bsl Index) == 0 -> @@ -1065,11 +1086,24 @@ decode_body(multipart_request, Binary) -> #ofp_meter_features_request{flags = Flags}; experimenter -> DataLength = size(Binary) - ?EXPERIMENTER_STATS_REQUEST_SIZE + ?OFP_HEADER_SIZE, - <> = Data, - #ofp_experimenter_request{flags = Flags, - experimenter = Experimenter, - exp_type = ExpType, data = ExpData} + Experimenter = get_id(experimenter_id, ExperimenterInt), + case Experimenter of + onf -> + ExpType = get_id(onf_multipart_msg_type, ExpTypeInt), + case ExpType of + onf_flow_monitor -> + Body = decode_flow_monitor(ExpData), + #onf_flow_monitor_request{flags = Flags, + body = Body} + end; + _ -> + #ofp_experimenter_request{flags = Flags, + experimenter = Experimenter, + exp_type = ExpTypeInt, + data = ExpData} + end end; decode_body(multipart_reply, Binary) -> <> = Binary, @@ -1230,6 +1264,7 @@ decode_body(meter_mod, Binary) -> #ofp_meter_mod{command = Command, flags = Flags, meter_id = MeterId, bands = Bands}. + %%%----------------------------------------------------------------------------- %%% Internal functions %%%----------------------------------------------------------------------------- diff --git a/src/ofp_v4_encode.erl b/src/ofp_v4_encode.erl index e1de5df..a9a8f76 100644 --- a/src/ofp_v4_encode.erl +++ b/src/ofp_v4_encode.erl @@ -344,7 +344,21 @@ encode_struct(#ofp_meter_config{flags = Flags, meter_id = MeterId, FlagsBin = flags_to_binary(meter_flag, Flags, 2), BandsBin = encode_list(Bands), Length = ?METER_CONFIG_SIZE + byte_size(BandsBin), - <>. + <>; +encode_struct(#onf_flow_monitor{id = Id, + flags = Flags, + out_port = OutPort, + table_id = TableId, + fields = Fields}) -> + FieldsBin = encode_list(Fields), + MatchLen = byte_size(FieldsBin), + Padding = ofp_utils:padding(MatchLen, 8) * 8, + FlagsBin = flags_to_binary(onf_flow_monitor_flags, Flags, 2), + OutPortInt = get_id(port_no, OutPort), + TableIdInt = get_id(table, TableId), + <>. encode_async_masks({PacketInMask1, PacketInMask2}, {PortStatusMask1, PortStatusMask2}, @@ -686,8 +700,9 @@ encode_body(#ofp_experimenter_request{flags = Flags, exp_type = ExpType, data = Data}) -> TypeInt = ofp_v4_enum:to_int(multipart_type, experimenter), FlagsBin = flags_to_binary(multipart_request_flags, Flags, 2), + ExperimenterInt = get_id(experimenter_id, Experimenter), <>; + ExperimenterInt:32, ExpType:32, Data/bytes>>; encode_body(#ofp_experimenter_reply{flags = Flags, experimenter = Experimenter, exp_type = ExpType, data = Data}) -> @@ -732,6 +747,17 @@ encode_body(#ofp_meter_mod{command = Command, MeterIdInt = get_id(meter_id, MeterId), BandsBin = encode_list(Bands), <>; + +%% ONF EXT-187 +encode_body(#onf_flow_monitor_request{flags = Flags, + body = Body}) -> + Data = encode_list(Body), + ExpTypeInt = get_id(onf_multipart_msg_type, onf_flow_monitor), + encode_body(#ofp_experimenter_request{flags=Flags, + experimenter=onf, + exp_type=ExpTypeInt, + data=Data}); + encode_body(Other) -> throw({bad_message, Other}). @@ -1087,6 +1113,8 @@ type_int(#ofp_get_async_reply{}) -> type_int(#ofp_set_async{}) -> ofp_v4_enum:to_int(type, set_async); type_int(#ofp_meter_mod{}) -> - ofp_v4_enum:to_int(type, meter_mod). + ofp_v4_enum:to_int(type, meter_mod); +type_int(#onf_flow_monitor_request{}) -> + ofp_v4_enum:to_int(type, multipart_request). diff --git a/src/ofp_v4_enum.erl b/src/ofp_v4_enum.erl index 1f8df10..86f4e2d 100644 --- a/src/ofp_v4_enum.erl +++ b/src/ofp_v4_enum.erl @@ -527,3 +527,20 @@ %% Echo Reply ------------------------------------------------------------------ %% Experimenter ---------------------------------------------------------------- +%% ONF Experimenter + +-enum({onf_multipart_msg_type, [{onf_flow_monitor, 1870}]}). + +%% EXT-187 + +-enum({onf_flow_monitor_flags, [initial, + add, + delete, + modify, + actions, + own]}). + +-enum({onf_flow_update_event, [added, + deleted, + modified, + abbrev]}).