Skip to content
Snippets Groups Projects
Commit a01a91e5 authored by Sebastien Merle's avatar Sebastien Merle
Browse files

First simple integration with the service component

parent b8096882
No related branches found
No related tags found
2 merge requests!142Release TeraFlowSDN 2.1,!133Integration of TE component
......@@ -67,8 +67,8 @@ get_flows() ->
update_flow(FlowId, LabelStack) ->
gen_server:call(?MODULE, {update_flow, FlowId, LabelStack}).
initiate_flow(Name, FromAddr, ToAddr, BindingLabel) ->
gen_server:call(?MODULE, {initiate_flow, Name, FromAddr, ToAddr,
initiate_flow(Name, From, To, BindingLabel) ->
gen_server:call(?MODULE, {initiate_flow, Name, From, To,
BindingLabel}, ?LARGE_TIMEOUT).
......@@ -111,19 +111,26 @@ handle_call({update_flow, FlowId, Labels}, From,
{noreply, State}
end
end;
handle_call({initiate_flow, Name, FromAddr, ToAddr, Binding}, From,
handle_call({initiate_flow, Name, FromKey, ToKey, Binding}, From,
#state{sessions = SessMap} = State) ->
case maps:find(FromAddr, SessMap) of
error -> {reply, {error, session_not_found}, State};
{ok, #sess{pid = Pid}} ->
case compute_path(FromAddr, ToAddr) of
{error, Reason} ->
{reply, {error, Reason}, State};
{ok, Labels} ->
InitRoute = routeinit_from_labels(Name, FromAddr, ToAddr,
[], Binding, Labels),
session_initiate_flow(State, Pid, InitRoute, From),
{noreply, State}
case {pcc_address(FromKey), pcc_address(ToKey)} of
{{error, Reason}, _} ->
{reply, {error, Reason}, State};
{_, {error, Reason}} ->
{reply, {error, Reason}, State};
{{ok, FromAddr}, {ok, ToAddr}} ->
case maps:find(FromAddr, SessMap) of
error -> {reply, {error, session_not_found}, State};
{ok, #sess{pid = Pid}} ->
case compute_path(FromAddr, ToAddr) of
{error, Reason} ->
{reply, {error, Reason}, State};
{ok, Labels} ->
InitRoute = routeinit_from_labels(Name, FromAddr,
ToAddr, [], Binding, Labels),
session_initiate_flow(State, Pid, InitRoute, From),
{noreply, State}
end
end
end;
handle_call({session_opened, Id, Caps, Pid}, _From,
......@@ -227,18 +234,33 @@ terminate(_Reason, _State) ->
%%% INTERNAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compute_path(From, To) ->
case epce_ted:compute_path(pcc_address, From, To) of
{ok, Devices} ->
Labels = tl([L || #{mpls_label := L} <- Devices, L =/= undefined]),
logger:debug("Route from ~p to ~p: ~p", [From, To, Labels]),
{ok, Labels};
ted_index(Id) when is_binary(Id) -> id;
ted_index({_, _, _, _}) -> pcc_address.
pcc_address(Key) ->
case epce_ted:lookup(ted_index(Key), Key) of
{error, Reason} ->
logger:warning("Failed to find a route from ~p to ~p: ~p",
[From, To, Reason]),
{error, route_not_found}
logger:warning("Failed to find a PCC address for router ~p: ~p",
[Key, Reason]),
{error, router_not_found};
{ok, #{pcc_address := Addr}} ->
{ok, Addr}
end.
compute_path(From, To) when is_binary(From), is_binary(To) ->
compute_path_result(From, To, epce_ted:compute_path(id, From, To));
compute_path({_, _, _, _} = From, {_, _, _, _} = To) ->
compute_path_result(From, To, epce_ted:compute_path(pcc_address, From, To)).
compute_path_result(From, To, {error, Reason}) ->
logger:warning("Failed to find a route from ~p to ~p: ~p",
[From, To, Reason]),
{error, route_not_found};
compute_path_result(From, To, {ok, Devices}) ->
Labels = tl([L || #{mpls_label := L} <- Devices, L =/= undefined]),
logger:debug("Route from ~p to ~p: ~p", [From, To, Labels]),
{ok, Labels}.
routereq_from_labels(Source, Destination, Constraints, Labels) ->
#{
source => Source,
......
......@@ -19,6 +19,7 @@
-export([link_updated/2]).
-export([link_deleted/1]).
-export([compute_path/3]).
-export([lookup/2]).
-export([get_graph/0]).
......@@ -69,6 +70,12 @@ compute_path(Index, From, To)
compute_path(Index, _From, _To) ->
{error, {invalid_index, Index}}.
lookup(Index, Key)
when Index =:= id; Index =:= pcc_address ->
gen_server:call(?MODULE, {lookup, Index, Key});
lookup(Index, _Key) ->
{error, {invalid_index, Index}}.
get_graph() ->
gen_server:call(?MODULE, get_graph).
......@@ -106,6 +113,13 @@ handle_call({compute_path, Index, From, To}, _From, #state{graph = G} = State) -
{error, Reason} ->
{reply, {error, Reason}, State}
end;
handle_call({lookup, Index, Key}, _From, #state{graph = G} = State) ->
case as_ids(State, Index, [Key]) of
{ok, [Id]} ->
{reply, do_lookup(G, Id), State};
{error, Reason} ->
{reply, {error, Reason}, State}
end;
handle_call(get_graph, _From, #state{graph = G} = State) ->
{reply, G, State};
handle_call(Request, _From, State) ->
......@@ -193,6 +207,12 @@ do_compute_path(G, FromId, ToId) ->
Ids -> {ok, retrieve_devices(G, Ids, [])}
end.
do_lookup(G, Id) ->
case digraph:vertex(G, Id) of
{_, Info} -> {ok, Info};
false -> {error, not_found}
end.
retrieve_devices(_G, [], Acc) ->
lists:reverse(Acc);
retrieve_devices(G, [Id | Rest], Acc) ->
......
......@@ -7,6 +7,7 @@
[kernel,
stdlib,
tfpb,
jsx,
epce
]},
{env,[]},
......
......@@ -16,6 +16,8 @@
-export([context_event/1]).
-export([topology_ready/1]).
-export([topology_event/1]).
-export([request_lsp/1]).
-export([delete_lsp/1]).
% Behaviour gen_statem functions
-export([init/1]).
......@@ -28,6 +30,7 @@
%%% Records %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-record(data, {
services = #{}
}).
......@@ -51,6 +54,12 @@ topology_ready(Topology) ->
topology_event(Event) ->
gen_statem:cast(?MODULE, {topology_event, Event}).
request_lsp(ServiceMap) ->
gen_statem:cast(?MODULE, {request_lsp, ServiceMap}).
delete_lsp(ServiceId) ->
gen_statem:cast(?MODULE, {delete_lsp, ServiceId}).
%%% BEHAVIOUR gen_statem FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......@@ -83,6 +92,17 @@ handle_event(cast, {topology_ready, _Topology}, ready, _Data) ->
handle_event(cast, {topology_event, _Event}, ready, _Data) ->
?LOG_DEBUG("Teraflow topology event: ~p", [_Event]),
keep_state_and_data;
handle_event({call, _From}, {request_lsp, ServiceMap}, ready, Data) ->
#{service_id := ServiceId} = ServiceMap,
?LOG_DEBUG("Teraflow service ~s requested its LSPs",
[format_service_id(ServiceId)]),
{Result, Data2} = do_request_lsp(Data, ServiceMap),
{keep_state, Data2, [{reply, Result}]};
handle_event(cast, {delete_lsp, ServiceId}, ready, Data) ->
?LOG_DEBUG("Teraflow service ~s delete its LSPs",
[format_service_id(ServiceId)]),
{Result, Data2} = do_delete_lsp(Data, ServiceId),
{keep_state, Data2, [{reply, Result}]};
%-- ANY STATE ------------------------------------------------------------------
handle_event(EventType, EventContent, State, Data) ->
?LOG_WARNING(Data, "Unexpected ~w event in state ~w: ~w",
......@@ -98,3 +118,42 @@ code_change(_OldVsn, OldState, OldData, _Extra) ->
%%% INTERNAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
format_service_id(#{context_id := #{context_uuid := #{uuid := ContextName}},
service_uuid := #{uuid := ServiceUUID}}) ->
iolist_to_binary(io_lib:format("~s:~s", [ContextName, ServiceUUID])).
do_request_lsp(#data{services = Services} = Data,
#{service_type := 'SERVICETYPE_TE'} = ServiceMap) ->
#{service_config := Config,
service_endpoint_ids := Endpoints,
service_id := ServiceId} = ServiceMap,
#{binding_label := BindingLabel1, symbolic_name := SymbolicName1}
= tfte_util:custom_config(Config, <<"/lsp-fw">>),
#{binding_label := BindingLabel2, symbolic_name := SymbolicName2}
= tfte_util:custom_config(Config, <<"/lsp-bw">>),
[#{device_id := #{device_uuid := #{uuid := Id1}}},
#{device_id := #{device_uuid := #{uuid := Id2}}}] = Endpoints,
case epce_server:initiate_flow(SymbolicName1, Id1, Id2, BindingLabel1) of
{error, Reason} ->
?LOG_ERROR("Error while setting up service ~s forward LSP: ~p",
[format_service_id(ServiceId), Reason]),
{'SERVICESTATUS_UNDEFINED', Data};
{ok, ForwardFlow} ->
case epce_server:initiate_flow(SymbolicName2, Id2, Id1, BindingLabel2) of
{error, Reason} ->
?LOG_ERROR("Error while setting up service ~s backward LSP: ~p",
[format_service_id(ServiceId), Reason]),
%TODO: Cleanup forward flow ?
{'SERVICESTATUS_UNDEFINED', Data};
{ok, BackwardFlow} ->
ServiceData = {ServiceMap, ForwardFlow, BackwardFlow},
Services2 = Services#{ServiceId => ServiceData},
Data2 = Data#data{services = Services2},
{'SERVICESTATUS_ACTIVE', Data2}
end
end.
do_delete_lsp(Data, ServiceId) ->
?LOG_INFO("LSP DELETION REQUESTED ~p", [ServiceId]),
{'SERVICESTATUS_UNDEFINED', Data}.
\ No newline at end of file
......@@ -6,6 +6,7 @@
%%% INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-include_lib("grpcbox/include/grpcbox.hrl").
-include_lib("kernel/include/logger.hrl").
%%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......@@ -18,14 +19,22 @@
%%% BEHAVIOUR te_te_service_bhvr CALLBACK FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%
request_lsp(_Ctx, _Service) ->
{error, {?GRPC_STATUS_UNIMPLEMENTED, <<"Not yet implemented">>},
#{headers => #{}, trailers => #{}}}.
request_lsp(_Ctx, Service) ->
?LOG_ERROR("Requesting LSP: ~p", [Service]),
try tfte_server:request_lsp(Service)
catch E:R:S ->
?LOG_ERROR("Error while requesting LSP: ~p:~p ~p", [E, R, S]),
'SERVICESTATUS_UNDEFINED'
end.
update_lsp(_Ctx, _Service) ->
update_lsp(_Ctx, _ServiceId) ->
{error, {?GRPC_STATUS_UNIMPLEMENTED, <<"Not yet implemented">>},
#{headers => #{}, trailers => #{}}}.
delete_lsp(_Ctx, _Service) ->
{error, {?GRPC_STATUS_UNIMPLEMENTED, <<"Not yet implemented">>},
#{headers => #{}, trailers => #{}}}.
delete_lsp(_Ctx, ServiceId) ->
?LOG_ERROR("Deleting LSP: ~p", [ServiceId]),
try tfte_server:delete_lsp(ServiceId)
catch E:R:S ->
?LOG_ERROR("Error while deleting LSP: ~p:~p ~p", [E, R, S]),
'SERVICESTATUS_UNDEFINED'
end.
......@@ -281,37 +281,31 @@ device_status(#{device_operational_status := 'DEVICEOPERATIONALSTATUS_ENABLED'})
enabled.
device_mpls_label(Device) ->
case device_config_value(<<"mpls_label">>, Device) of
case device_config_value(<<"/te_data/mpls_label">>, Device) of
undefined -> undefined;
LabelBin ->
try binary_to_integer(LabelBin)
LabelJson ->
try jsx:decode(LabelJson)
catch error:badarg -> undefined
end
end.
device_pcc_address(Device) ->
case device_config_value(<<"pcc_address">>, Device) of
case device_config_value(<<"/te_data/pcc_address">>, Device) of
undefined -> undefined;
AddressBin ->
case inet_parse:address(binary_to_list(AddressBin)) of
{ok, Address} -> Address;
{error,einval} -> undefined
AddressJson ->
try jsx:decode(AddressJson) of
AddressBin ->
case inet_parse:address(binary_to_list(AddressBin)) of
{ok, Address} -> Address;
{error,einval} -> undefined
end
catch
error:badarg -> undefined
end
end.
device_config_value(Key, #{device_config := #{config_rules := Rules}}) ->
device_config_value(Key, Rules);
device_config_value(_Key, []) ->
undefined;
device_config_value(Key, [#{action := 'CONFIGACTION_SET',
config_rule := {custom, Rule}} | Rest]) ->
case Rule of
#{resource_key := Key, resource_value := Value} -> Value;
_ -> device_config_value(Key, Rest)
end;
device_config_value(Key, [_Rule | Rest]) ->
device_config_value(Key, Rest).
device_config_value(Key, #{device_config := Config}) ->
tfte_util:custom_config(Config, Key).
device_endpoints(Device) ->
device_endpoints(Device, []).
......
-module(tfte_util).
%%% INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-include_lib("kernel/include/logger.hrl").
%%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% API functions
-export([custom_config/2]).
%%% API FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
custom_config(#{config_rules := Rules}, Key) ->
custom_config(Rules, Key);
custom_config([], _Key) ->
undefined;
custom_config([#{action := 'CONFIGACTION_SET',
config_rule := {custom, Rule}} | Rest], Key) ->
case Rule of
#{resource_key := Key, resource_value := Value} -> jsx:decode(Value);
_ -> custom_config(Rest, Key)
end;
custom_config([_Rule | Rest], Key) ->
custom_config(Rest, Key).
......@@ -2,6 +2,7 @@
{deps, [
grpcbox,
jsx,
{pcep_server, {git, "https://github.com/stritzinger/pcep_server.git", {branch, "master"}}}
]}.
......@@ -17,6 +18,7 @@
runtime_tools,
epce,
grpcbox,
jsx,
tfpb,
tfte
]},
......
......@@ -9,6 +9,7 @@
{<<"gproc">>,{pkg,<<"gproc">>,<<"0.8.0">>},1},
{<<"grpcbox">>,{pkg,<<"grpcbox">>,<<"0.15.0">>},0},
{<<"hpack">>,{pkg,<<"hpack_erl">>,<<"0.2.3">>},2},
{<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},0},
{<<"pcep_codec">>,
{git,"https://github.com/stritzinger/pcep_codec.git",
{ref,"ca5eb0822d9971ec4bcfb427a49b2e516081a126"}},
......@@ -26,6 +27,7 @@
{<<"gproc">>, <<"CEA02C578589C61E5341FCE149EA36CCEF236CC2ECAC8691FBA408E7EA77EC2F">>},
{<<"grpcbox">>, <<"97C7126296A091602D372EBF5860A04F7BC795B45B33A984CAD2B8E362774FD8">>},
{<<"hpack">>, <<"17670F83FF984AE6CD74B1C456EDDE906D27FF013740EE4D9EFAA4F1BF999633">>},
{<<"jsx">>, <<"D12516BAA0BB23A59BB35DCCAF02A1BD08243FCBB9EFE24F2D9D056CCFF71268">>},
{<<"ranch">>, <<"FBF3D79661C071543256F9051CAF19D65DAA6DF1CF6824D8F37A49B19A66F703">>}]},
{pkg_hash_ext,[
{<<"acceptor_pool">>, <<"0CBCD83FDC8B9AD2EEE2067EF8B91A14858A5883CB7CD800E6FCD5803E158788">>},
......@@ -34,5 +36,6 @@
{<<"gproc">>, <<"580ADAFA56463B75263EF5A5DF4C86AF321F68694E7786CB057FD805D1E2A7DE">>},
{<<"grpcbox">>, <<"161ABE9E17E7D1982EFA6488ADEAA13C3E847A07984A6E6B224E553368918647">>},
{<<"hpack">>, <<"06F580167C4B8B8A6429040DF36CC93BBA6D571FAEAEC1B28816523379CBB23A">>},
{<<"jsx">>, <<"0C5CC8FDC11B53CC25CF65AC6705AD39E54ECC56D1C22E4ADB8F5A53FB9427F3">>},
{<<"ranch">>, <<"C20A4840C7D6623C19812D3A7C828B2F1BD153EF0F124CB69C54FE51D8A42AE0">>}]}
].
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment