Commit a01a91e5 authored by Sebastien Merle's avatar Sebastien Merle
Browse files

First simple integration with the service component

parent b8096882
Loading
Loading
Loading
Loading
+45 −23
Original line number Original line Diff line number Diff line
@@ -67,8 +67,8 @@ get_flows() ->
update_flow(FlowId, LabelStack) ->
update_flow(FlowId, LabelStack) ->
    gen_server:call(?MODULE, {update_flow, FlowId, LabelStack}).
    gen_server:call(?MODULE, {update_flow, FlowId, LabelStack}).


initiate_flow(Name, FromAddr, ToAddr, BindingLabel) ->
initiate_flow(Name, From, To, BindingLabel) ->
    gen_server:call(?MODULE, {initiate_flow, Name, FromAddr, ToAddr,
    gen_server:call(?MODULE, {initiate_flow, Name, From, To,
                              BindingLabel}, ?LARGE_TIMEOUT).
                              BindingLabel}, ?LARGE_TIMEOUT).




@@ -111,8 +111,14 @@ handle_call({update_flow, FlowId, Labels}, From,
                    {noreply, State}
                    {noreply, State}
            end
            end
    end;
    end;
handle_call({initiate_flow, Name, FromAddr, ToAddr, Binding}, From,
handle_call({initiate_flow, Name, FromKey, ToKey, Binding}, From,
            #state{sessions = SessMap} = State) ->
            #state{sessions = SessMap} = 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
            case maps:find(FromAddr, SessMap) of
                error -> {reply, {error, session_not_found}, State};
                error -> {reply, {error, session_not_found}, State};
                {ok, #sess{pid = Pid}} ->
                {ok, #sess{pid = Pid}} ->
@@ -120,11 +126,12 @@ handle_call({initiate_flow, Name, FromAddr, ToAddr, Binding}, From,
                        {error, Reason} ->
                        {error, Reason} ->
                            {reply, {error, Reason}, State};
                            {reply, {error, Reason}, State};
                        {ok, Labels} ->
                        {ok, Labels} ->
                    InitRoute = routeinit_from_labels(Name, FromAddr, ToAddr,
                            InitRoute = routeinit_from_labels(Name, FromAddr,
                                                      [], Binding, Labels),
                                            ToAddr, [], Binding, Labels),
                            session_initiate_flow(State, Pid, InitRoute, From),
                            session_initiate_flow(State, Pid, InitRoute, From),
                            {noreply, State}
                            {noreply, State}
                    end
                    end
            end
    end;
    end;
handle_call({session_opened, Id, Caps, Pid}, _From,
handle_call({session_opened, Id, Caps, Pid}, _From,
            #state{sessions = SessMap, sess_pids = SessPids} = State) ->
            #state{sessions = SessMap, sess_pids = SessPids} = State) ->
@@ -227,17 +234,32 @@ terminate(_Reason, _State) ->


%%% INTERNAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% INTERNAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


compute_path(From, To) ->
ted_index(Id) when is_binary(Id) -> id;
    case epce_ted:compute_path(pcc_address, From, To) of
ted_index({_, _, _, _}) -> pcc_address.
        {ok, Devices} ->

            Labels = tl([L || #{mpls_label := L} <- Devices, L =/= undefined]),
pcc_address(Key) ->
            logger:debug("Route from ~p to ~p: ~p", [From, To, Labels]),
    case epce_ted:lookup(ted_index(Key), Key) of
            {ok, Labels};
        {error, Reason} ->
        {error, Reason} ->
            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",
    logger:warning("Failed to find a route from ~p to ~p: ~p",
                   [From, To, Reason]),
                   [From, To, Reason]),
            {error, route_not_found}
    {error, route_not_found};
    end.
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) ->
routereq_from_labels(Source, Destination, Constraints, Labels) ->
    #{
    #{
+20 −0
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
-export([link_updated/2]).
-export([link_updated/2]).
-export([link_deleted/1]).
-export([link_deleted/1]).
-export([compute_path/3]).
-export([compute_path/3]).
-export([lookup/2]).


-export([get_graph/0]).
-export([get_graph/0]).


@@ -69,6 +70,12 @@ compute_path(Index, From, To)
compute_path(Index, _From, _To) ->
compute_path(Index, _From, _To) ->
    {error, {invalid_index, Index}}.
    {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() ->
get_graph() ->
    gen_server:call(?MODULE, 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} ->
        {error, Reason} ->
            {reply, {error, Reason}, State}
            {reply, {error, Reason}, State}
    end;
    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) ->
handle_call(get_graph, _From, #state{graph = G} = State) ->
    {reply, G, State};
    {reply, G, State};
handle_call(Request, _From, State) ->
handle_call(Request, _From, State) ->
@@ -193,6 +207,12 @@ do_compute_path(G, FromId, ToId) ->
        Ids -> {ok, retrieve_devices(G, Ids, [])}
        Ids -> {ok, retrieve_devices(G, Ids, [])}
    end.
    end.


do_lookup(G, Id) ->
    case digraph:vertex(G, Id) of
        {_, Info} -> {ok, Info};
        false -> {error, not_found}
    end.

retrieve_devices(_G, [], Acc) ->
retrieve_devices(_G, [], Acc) ->
    lists:reverse(Acc);
    lists:reverse(Acc);
retrieve_devices(G, [Id | Rest], Acc) ->
retrieve_devices(G, [Id | Rest], Acc) ->
+1 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
   [kernel,
   [kernel,
    stdlib,
    stdlib,
    tfpb,
    tfpb,
    jsx,
    epce
    epce
   ]},
   ]},
  {env,[]},
  {env,[]},
+59 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@
-export([context_event/1]).
-export([context_event/1]).
-export([topology_ready/1]).
-export([topology_ready/1]).
-export([topology_event/1]).
-export([topology_event/1]).
-export([request_lsp/1]).
-export([delete_lsp/1]).


% Behaviour gen_statem functions
% Behaviour gen_statem functions
-export([init/1]).
-export([init/1]).
@@ -28,6 +30,7 @@
%%% Records %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Records %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


-record(data, {
-record(data, {
    services = #{}
}).
}).




@@ -51,6 +54,12 @@ topology_ready(Topology) ->
topology_event(Event) ->
topology_event(Event) ->
    gen_statem:cast(?MODULE, {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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% BEHAVIOUR gen_statem FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


@@ -83,6 +92,17 @@ handle_event(cast, {topology_ready, _Topology}, ready, _Data) ->
handle_event(cast, {topology_event, _Event}, ready, _Data) ->
handle_event(cast, {topology_event, _Event}, ready, _Data) ->
    ?LOG_DEBUG("Teraflow topology event: ~p", [_Event]),
    ?LOG_DEBUG("Teraflow topology event: ~p", [_Event]),
    keep_state_and_data;
    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 ------------------------------------------------------------------
%-- ANY STATE ------------------------------------------------------------------
handle_event(EventType, EventContent, State, Data) ->
handle_event(EventType, EventContent, State, Data) ->
    ?LOG_WARNING(Data, "Unexpected ~w event in state ~w: ~w",
    ?LOG_WARNING(Data, "Unexpected ~w event in state ~w: ~w",
@@ -98,3 +118,42 @@ code_change(_OldVsn, OldState, OldData, _Extra) ->




%%% INTERNAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% 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
+16 −7
Original line number Original line Diff line number Diff line
@@ -6,6 +6,7 @@
%%% INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


-include_lib("grpcbox/include/grpcbox.hrl").
-include_lib("grpcbox/include/grpcbox.hrl").
-include_lib("kernel/include/logger.hrl").




%%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -18,14 +19,22 @@


%%% BEHAVIOUR te_te_service_bhvr CALLBACK FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% BEHAVIOUR te_te_service_bhvr CALLBACK FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%


request_lsp(_Ctx, _Service) ->
request_lsp(_Ctx, Service) ->
    {error, {?GRPC_STATUS_UNIMPLEMENTED, <<"Not yet implemented">>},
    ?LOG_ERROR("Requesting LSP: ~p", [Service]),
             #{headers => #{}, trailers => #{}}}.
    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">>},
    {error, {?GRPC_STATUS_UNIMPLEMENTED, <<"Not yet implemented">>},
             #{headers => #{}, trailers => #{}}}.
             #{headers => #{}, trailers => #{}}}.


delete_lsp(_Ctx, _Service) ->
delete_lsp(_Ctx, ServiceId) ->
    {error, {?GRPC_STATUS_UNIMPLEMENTED, <<"Not yet implemented">>},
    ?LOG_ERROR("Deleting LSP: ~p", [ServiceId]),
             #{headers => #{}, trailers => #{}}}.
    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.
Loading