Skip to content

Commit fb809d0

Browse files
committed
Use dby:search in dobby_oflib:get_path
Search through Dobby's graph to find a path, and populate a fresh digraph with the nodes and edges along the path.
1 parent 2460106 commit fb809d0

1 file changed

Lines changed: 76 additions & 2 deletions

File tree

src/dobby_oflib.erl

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,18 @@
2222
{ok, Path :: digraph:graph()} | {error, Reason :: term()}.
2323

2424
get_path(SrcEndpoint, DstEndpoint) ->
25-
{ok, digraph:new()}.
25+
case dby:search(
26+
vertices_edges_search_fun(SrcEndpoint, DstEndpoint),
27+
not_found,
28+
SrcEndpoint,
29+
[breadth, {max_depth, 100}]) of
30+
Path = [_|_] ->
31+
Digraph = digraph:new(),
32+
insert_path(Path, Digraph),
33+
{ok, Digraph};
34+
not_found ->
35+
{error, no_path}
36+
end.
2637

2738
%% @doc Publish a Net Flow between two endpoints to Dobby.
2839
%%
@@ -102,4 +113,67 @@ reconstruct_flow_path(FlowPath0) ->
102113
FlowPath1 = lists:map(Fun, FlowPath0),
103114
lists:flatten(FlowPath1).
104115

105-
116+
%% This function returns a function to be passed to dby:search.
117+
vertices_edges_search_fun(Ep1, Ep2) ->
118+
fun(Id, #{<<"type">> := <<"endpoint">>}, [], Acc) when Id =:= Ep1 ->
119+
%% This is the starting point.
120+
{continue, Acc};
121+
(Id,
122+
#{<<"type">> := <<"endpoint">>} = NodeMetadata,
123+
[{_, #{<<"type">> := <<"of_port">>}, #{<<"type">> := <<"connected_to">>}} | _] = Path,
124+
Acc) ->
125+
%% We've found an endpoint. That's only interesting if
126+
%% it's the endpoint we're looking for.
127+
if Id =:= Ep2 ->
128+
%% If so, stop and return the path.
129+
{stop, lists:reverse(Path, [{Id, NodeMetadata, #{}}])};
130+
true ->
131+
%% Otherwise, keep going.
132+
{skip, Acc}
133+
end;
134+
(_Id,
135+
#{<<"type">> := Type2},
136+
[{_, #{<<"type">> := Type1}, #{<<"type">> := EdgeType}} | _],
137+
Acc) ->
138+
case valid_edge(Type1, EdgeType, Type2) of
139+
true ->
140+
{continue, Acc};
141+
false ->
142+
{skip, Acc}
143+
end
144+
end.
145+
146+
-spec valid_edge(Node1Type :: binary(),
147+
EdgeType :: binary(),
148+
Node2Type :: binary()) -> boolean().
149+
%% @doc
150+
%% Return true if we should follow an edge of type `EdgeType' from a
151+
%% node of type `Node1Type' to a node of type `Node2Type'.
152+
valid_edge(<<"endpoint">>, <<"connected_to">>, <<"of_port">>) ->
153+
true;
154+
valid_edge(<<"of_port">>, <<"port_of">>, <<"of_switch">>) ->
155+
true;
156+
valid_edge(<<"of_switch">>, <<"port_of">>, <<"of_port">>) ->
157+
true;
158+
valid_edge(<<"of_port">>, <<"connected_to">>, <<"of_port">>) ->
159+
true;
160+
valid_edge(_, _, _) ->
161+
false.
162+
163+
insert_path([{NodeId, NodeMetadata, EdgeMetadata} | Rest],
164+
Digraph) ->
165+
%% Insert the first node as a vertex.
166+
digraph:add_vertex(Digraph, NodeId, NodeMetadata),
167+
%% Then recurse through the rest of the list, adding edges as we
168+
%% go along.
169+
insert_path(Rest, NodeId, EdgeMetadata, Digraph).
170+
171+
insert_path([], _, _, _) ->
172+
ok;
173+
insert_path([{NodeId, NodeMetadata, NextEdgeMetadata} | Rest],
174+
PreviousNodeId, EdgeMetadata, Digraph) ->
175+
digraph:add_vertex(Digraph, NodeId, NodeMetadata),
176+
%% We want bidirectional edges:
177+
digraph:add_edge(Digraph, PreviousNodeId, NodeId, EdgeMetadata),
178+
digraph:add_edge(Digraph, NodeId, PreviousNodeId, EdgeMetadata),
179+
insert_path(Rest, NodeId, NextEdgeMetadata, Digraph).

0 commit comments

Comments
 (0)