Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement some parts of OpenFlow Extensions for 1.3.X Pack 1 #66

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 67 additions & 2 deletions include/ofp_v4.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -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) -------------------------------------------------

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1563,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()]
}).
74 changes: 62 additions & 12 deletions src/ofp_v4_decode.erl
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,40 @@ decode_match_field(<<Header:4/bytes, Binary/bytes>>) ->
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 ->
<<ExpInt:32, Binary3/bytes>> = Binary,
Exp = get_id(experimenter_id, ExpInt),
case Exp of
onf ->
%% EXT-256
%% see the comment in encode_struct/1 for the weirdness
<<ExpTypeInt:16, Binary4/bytes>> = 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 ->
<<Value:Length/bytes, Rest/bytes>> = Binary,
<<Value:ByteLength/bytes, Rest/bytes>> = Binary2,
TLV = #ofp_field{value = ofp_utils:uncut_bits(Value, BitLength)};
true ->
Length2 = (Length div 2),
<<Value:Length2/bytes, Mask:Length2/bytes,
Rest/bytes>> = Binary,
ByteLength2 = (ByteLength div 2),
<<Value:ByteLength2/bytes, Mask:ByteLength2/bytes,
Rest/bytes>> = 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}.

Expand Down Expand Up @@ -797,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(<<Id:32, FlagsBin:2/bytes, MatchLen:16,
OutPortInt:32, TableIdInt:8, _:24,
Rest/bytes>>, 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,
<<FieldsBin:MatchLen/bytes, _:PadBits, Rest2/bytes>> = 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 ->
Expand Down Expand Up @@ -1050,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,
<<Experimenter:32, ExpType:32,
<<ExperimenterInt:32, ExpTypeInt:32,
ExpData:DataLength/bytes>> = 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) ->
<<TypeInt:16, FlagsBin:16/bits, _Pad:32, Data/bytes>> = Binary,
Expand Down Expand Up @@ -1215,6 +1264,7 @@ decode_body(meter_mod, Binary) ->
#ofp_meter_mod{command = Command, flags = Flags, meter_id = MeterId,
bands = Bands}.


%%%-----------------------------------------------------------------------------
%%% Internal functions
%%%-----------------------------------------------------------------------------
Expand Down
71 changes: 62 additions & 9 deletions src/ofp_v4_encode.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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 = <<Value2/bytes, Mask2/bytes>>,
Len2 = byte_size(Value2) * 2;
Rest = <<Value2/bytes, Mask2/bytes>>;
false ->
HasMaskInt = 0,
Rest = <<Value2/bytes>>,
Len2 = byte_size(Value2)
Rest = <<Value2/bytes>>
end,
<<ClassInt:16, FieldInt:7, HasMaskInt:1, Len2:8, Rest/bytes>>;
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),
<<ExpTypeInt:16, Rest/bytes>>
end,
<<ExpId:32, Rest3/bytes>>;
_ ->
Rest
end,
Len2 = byte_size(Rest2),
<<ClassInt:16, FieldInt:7, HasMaskInt:1, Len2:8, Rest2/bytes>>;

encode_struct(#ofp_port{port_no = PortNo, hw_addr = HWAddr, name = Name,
config = Config, state = State, curr = Curr,
Expand Down Expand Up @@ -319,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),
<<Length:16, FlagsBin:16/bits, MeterIdInt:32, BandsBin/bytes>>.
<<Length:16, FlagsBin:16/bits, MeterIdInt:32, BandsBin/bytes>>;
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),
<<Id:32, FlagsBin:2/bytes, MatchLen:16,
OutPortInt:32, TableIdInt:8, 0:24,
FieldsBin/bytes, 0:Padding>>.

encode_async_masks({PacketInMask1, PacketInMask2},
{PortStatusMask1, PortStatusMask2},
Expand Down Expand Up @@ -661,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),
<<TypeInt:16, FlagsBin:2/bytes, 0:32,
Experimenter:32, ExpType:32, Data/bytes>>;
ExperimenterInt:32, ExpType:32, Data/bytes>>;
encode_body(#ofp_experimenter_reply{flags = Flags,
experimenter = Experimenter,
exp_type = ExpType, data = Data}) ->
Expand Down Expand Up @@ -707,6 +747,17 @@ encode_body(#ofp_meter_mod{command = Command,
MeterIdInt = get_id(meter_id, MeterId),
BandsBin = encode_list(Bands),
<<CommandInt:16, FlagsBin:2/bytes, MeterIdInt:32, BandsBin/bytes>>;

%% 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}).

Expand Down Expand Up @@ -1062,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).


24 changes: 24 additions & 0 deletions src/ofp_v4_enum.erl
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@
pause,
pause_asym]}).

-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 ------------------------------------------------------------

%% Note: Not in the specification
Expand Down Expand Up @@ -169,6 +174,8 @@
tunnel_id,
ipv6_exthdr]}).

-enum({oxm_onf_match_fields, [{pbb_uca, 2560}]}). %% EXT-256

-enum({vlan_id, [none,
{present, 16#1000}]}).

Expand Down Expand Up @@ -520,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]}).
3 changes: 2 additions & 1 deletion src/ofp_v4_map.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
%%
Expand Down
3 changes: 3 additions & 0 deletions src/ofp_v4_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -467,6 +469,7 @@ mpls_bos(Val) ->

% eth_type=0x88e7
%% pbb_isid
%% pbb_uca

%% tunnel_id

Expand Down