|
22 | 22 | {ok, Path :: digraph:graph()} | {error, Reason :: term()}. |
23 | 23 |
|
24 | 24 | 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. |
26 | 37 |
|
27 | 38 | %% @doc Publish a Net Flow between two endpoints to Dobby. |
28 | 39 | %% |
@@ -102,4 +113,67 @@ reconstruct_flow_path(FlowPath0) -> |
102 | 113 | FlowPath1 = lists:map(Fun, FlowPath0), |
103 | 114 | lists:flatten(FlowPath1). |
104 | 115 |
|
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