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

Add support for PCE initiated LSPs

parent 23dfc1b3
No related branches found
No related tags found
No related merge requests found
......@@ -17,6 +17,7 @@
-export([init/1]).
-export([opened/4]).
-export([flow_added/2]).
-export([flow_initiated/2]).
-export([ready/1]).
-export([request_route/2]).
-export([flow_delegated/2]).
......@@ -49,6 +50,10 @@ flow_added(Flow, State) ->
ok -> {ok, State}
end.
flow_initiated(Flow, State) ->
ok = epce_server:flow_initiated(Flow),
{ok, State}.
ready(State) ->
{ok, State}.
......
......@@ -15,10 +15,12 @@
-export([start_link/0]).
-export([get_flows/0]).
-export([update_flow/2]).
-export([initiate_flow/4]).
% Handler Functions
-export([session_opened/3]).
-export([flow_added/1]).
-export([flow_initiated/1]).
-export([request_route/1]).
-export([flow_status_changed/2]).
......@@ -32,6 +34,11 @@
-export([terminate/2]).
%%% MACROS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(LARGE_TIMEOUT, 20000).
%%% RECORDS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-record(sess, {
......@@ -60,6 +67,10 @@ 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,
BindingLabel}, ?LARGE_TIMEOUT).
%%% HANDLER FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......@@ -69,6 +80,9 @@ session_opened(Id, Caps, Pid) ->
flow_added(Flow) ->
gen_server:call(?MODULE, {flow_added, Flow}).
flow_initiated(Flow) ->
gen_server:call(?MODULE, {flow_initiated, Flow}).
request_route(RouteReq) ->
gen_server:call(?MODULE, {request_route, RouteReq}).
......@@ -92,11 +106,26 @@ handle_call({update_flow, FlowId, Labels}, From,
error -> {reply, {error, session_not_found}, State};
{ok, #sess{pid = Pid}} ->
#{source := S, destination := D, constraints := C} = R,
ReqRoute = route_from_labels(S, D, C, Labels),
ReqRoute = routereq_from_labels(S, D, C, Labels),
session_update_flow(State, Pid, FlowId, ReqRoute, From),
{noreply, State}
end
end;
handle_call({initiate_flow, Name, FromAddr, ToAddr, 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}
end
end;
handle_call({session_opened, Id, Caps, Pid}, _From,
#state{sessions = SessMap, sess_pids = SessPids} = State) ->
logger:debug("Session with capabilities ~w open to ~w", [Caps, Id]),
......@@ -114,6 +143,11 @@ handle_call({flow_added, #{id := Id, route := Route} = Flow},
_From, #state{flows = Flows} = State) ->
logger:debug("Flow ~w with route ~w added", [Id, route_to_labels(Route)]),
{reply, ok, State#state{flows = Flows#{Id => Flow}}};
handle_call({flow_initiated, #{id := Id, route := Route} = Flow},
_From, #state{flows = Flows} = State) ->
logger:debug("Flow ~w with route ~p initiated",
[Id, route_to_labels(Route)]),
{reply, ok, State#state{flows = Flows#{Id => Flow}}};
handle_call({request_route, RouteReq}, _From, State) ->
logger:info("Route from ~w to ~w requested",
[maps:get(source, RouteReq), maps:get(destination, RouteReq)]),
......@@ -122,7 +156,7 @@ handle_call({request_route, RouteReq}, _From, State) ->
{error, _Reason} = Error ->
{reply, Error, State};
{ok, Labels} ->
Route = route_from_labels(S, D, C, Labels),
Route = routereq_from_labels(S, D, C, Labels),
{reply, {ok, Route}, State}
end;
handle_call({flow_status_changed, FlowId, NewStatus}, _From,
......@@ -131,12 +165,13 @@ handle_call({flow_status_changed, FlowId, NewStatus}, _From,
Flow = maps:get(FlowId, Flows),
{reply, ok, State#state{
flows = maps:put(FlowId, Flow#{status := NewStatus}, Flows)}};
handle_call(Request, _From, State) ->
logger:warning("Unexpected request ~w", [Request]),
handle_call(Request, From, State) ->
logger:warning("Unexpected call from ~w: ~p", [From, Request]),
{reply, {error, unexpected_call}, State}.
handle_cast(_Request, State) ->
handle_cast(Request, State) ->
logger:warning("Unexpected cast: ~p", [Request]),
{noreply, State}.
handle_continue(_Continue, State) ->
......@@ -153,7 +188,17 @@ handle_info({flow_updated, FlowId, NewRoute, From},
{noreply, State#state{flows = Flows2}}
end;
handle_info({flow_update_error, FlowId, Reason, From}, State) ->
logger:error("Flow ~w updated error: ~w", [FlowId, Reason]),
logger:error("Flow ~w updated error: ~p", [FlowId, Reason]),
gen_server:reply(From, {error, Reason}),
{noreply, State};
handle_info({flow_initiated, #{id := FlowId, route := Route} = Flow, From},
#state{flows = Flows} = State) ->
logger:info("Flow ~w initiated to ~p",
[FlowId, route_to_labels(Route)]),
gen_server:reply(From, {ok, FlowId}),
{noreply, State#state{flows = Flows#{FlowId => Flow}}};
handle_info({flow_init_error, Reason, From}, State) ->
logger:error("Flow initialisation error: ~p", [Reason]),
gen_server:reply(From, {error, Reason}),
{noreply, State};
handle_info({'DOWN', MonRef, process, Pid, _Reason},
......@@ -169,7 +214,8 @@ handle_info({'DOWN', MonRef, process, Pid, _Reason},
_X ->
{noreply, State}
end;
handle_info(_Info, State) ->
handle_info(Info, State) ->
logger:warning("Unexpected message: ~p", [Info]),
{noreply, State}.
code_change(_OldVsn, State, _Extra) ->
......@@ -189,10 +235,10 @@ compute_path(From, To) ->
{ok, Labels};
{error, Reason} ->
logger:warning("Failed to find a route from ~p to ~p", [From, To]),
{error, Reason}
{error, route_not_found}
end.
route_from_labels(Source, Destination, Constraints, Labels) ->
routereq_from_labels(Source, Destination, Constraints, Labels) ->
#{
source => Source,
destination => Destination,
......@@ -207,6 +253,13 @@ route_from_labels(Source, Destination, Constraints, Labels) ->
]
}.
routeinit_from_labels(Name, Source, Destination, Constraints, Binding, Labels) ->
Route = routereq_from_labels(Source, Destination, Constraints, Labels),
Route#{
name => Name,
binding_label => Binding
}.
route_to_labels(#{steps := Steps}) ->
[Sid#mpls_stack_entry.label || #{sid := Sid} <- Steps].
......@@ -216,6 +269,9 @@ route_to_labels(#{steps := Steps}) ->
session_update_flow(#state{bouncer = Pid}, SessPid, FlowId, Route, Args) ->
Pid ! {update_flow, SessPid, FlowId, Route, Args}.
session_initiate_flow(#state{bouncer = Pid}, SessPid, Route, Args) ->
Pid ! {initiate_flow, SessPid, Route, Args}.
bouncer_start(#state{bouncer = undefined} = State) ->
Self = self(),
Pid = erlang:spawn_link(fun() ->
......@@ -238,5 +294,14 @@ bouncer_loop(Parent) ->
{error, Reason} ->
Parent ! {flow_update_error, FlowId, Reason, Args},
bouncer_loop(Parent)
end;
{initiate_flow, SessPid, InitRoute, Args} ->
case pcep_server_session:initiate_flow(SessPid, InitRoute) of
{ok, Flow} ->
Parent ! {flow_initiated, Flow, Args},
bouncer_loop(Parent);
{error, Reason} ->
Parent ! {flow_init_error, Reason, Args},
bouncer_loop(Parent)
end
end.
......@@ -11,11 +11,11 @@
{<<"hpack">>,{pkg,<<"hpack_erl">>,<<"0.2.3">>},2},
{<<"pcep_codec">>,
{git,"git@github.com:stritzinger/pcep_codec.git",
{ref,"3d1623fdf0c62d3daf400ac65aaf985f8bd40835"}},
{ref,"84dcc430b2aa427984c100cc19dd35d946b22ff9"}},
1},
{<<"pcep_server">>,
{git,"git@github.com:stritzinger/pcep_server.git",
{ref,"2cf692e7e5fa2e9ac0fd54e5aa64ffb17f4f1b4a"}},
{ref,"3910bf5546879cb91a3483008b6aed11753deaa6"}},
0},
{<<"ranch">>,{pkg,<<"ranch">>,<<"2.0.0">>},1}]}.
[
......
......@@ -103,17 +103,11 @@ routers:
debug pathd pcep basic
segment-routing
traffic-eng
mpls-te on
policy color 1 endpoint 6.6.6.6
name DEFAULT
binding-sid 1111
candidate-path preference 100 name RUNTIME dynamic
!
!
pcep
pce-config CONFIG
source-address ip 1.1.1.1
pce PCE
pce-initiated
address ip ${PCE_IP}
config CONFIG
pcc
......@@ -438,16 +432,11 @@ routers:
debug pathd pcep
segment-routing
traffic-eng
policy color 1 endpoint 1.1.1.1
name DEFAULT
binding-sid 6666
candidate-path preference 200 name RUNTIME dynamic
!
!
pcep
pce-config CONFIG
source-address ip 6.6.6.6
pce PCE
pce-initiated
address ip ${PCE_IP}
config CONFIG
pcc
......
......@@ -41,7 +41,5 @@ cat "${ROOTDIR}/2-6-netgen-topology.yml.template" | envsubst > "${RUNDIR}/topolo
sudo -i bash -c "\
cd ${RUNDIR}/netgen;\
sysctl -w net.ipv6.conf.all.disable_ipv6=1;\
sysctl -w net.ipv6.conf.default.disable_ipv6=1;\
sysctl -w net.ipv4.conf.all.rp_filter=0;\
PATH=/usr/lib/frr:\$PATH ./exe/netgen ../topology.yml -c ../config.yml"
......@@ -89,3 +89,20 @@ Then in second console:
$ sudo -i
# cd /tmp/negen
# ./tmux.sh
### Setup a flow from the Erlang console
We will setup two unidirectional flow between router 1 and 6.
We will use the binding label 1111 for the flow from router 1 to router 6, and the binding label 6666 for the flow from router 6 to router 1.
$ kubectl --namespace tfs exec -ti $(kubectl --namespace tfs get pods --selector=app=teservice -o name) -- /tfte/bin/tfte remote_console
1> {ok, Flow1to6} = epce_server:initiate_flow(<<"foo">>, {1, 1, 1, 1}, {6, 6, 6, 6}, 1111).
2> {ok, Flow6to1} = epce_server:initiate_flow(<<"bar">>, {6, 6, 6, 6}, {1, 1, 1, 1}, 6666).
Now if we go to the tmux session src (Ctrl-B 0) we can ping dst:
$ ping 9.9.9.2
From the Erlang console we can update the initiated flows to change the path the packets are flowing through:
3> epce_server:update_flow(Flow6to1, [16050, 16030, 16010]).
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