Open Kilda Java Documentation
NeoDriver.java
Go to the documentation of this file.
1 /* Copyright 2017 Telstra Open Source
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package org.openkilda.pce.provider;
17 
18 import static org.openkilda.pce.Utils.safeAsInt;
19 
34 
35 import org.apache.commons.lang3.tuple.Pair;
36 import org.neo4j.driver.v1.AccessMode;
37 import org.neo4j.driver.v1.Driver;
38 import org.neo4j.driver.v1.Record;
39 import org.neo4j.driver.v1.Session;
40 import org.neo4j.driver.v1.StatementResult;
41 import org.neo4j.driver.v1.Value;
42 import org.neo4j.driver.v1.Values;
43 import org.neo4j.driver.v1.exceptions.ClientException;
44 import org.neo4j.driver.v1.exceptions.TransientException;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 
48 import java.util.ArrayList;
49 import java.util.LinkedList;
50 import java.util.List;
51 
52 public class NeoDriver implements PathComputer {
53 
54  private static final Logger logger = LoggerFactory.getLogger(NeoDriver.class);
55 
56  private final Driver driver;
57 
58  public NeoDriver(Driver driver) {
59  this.driver = driver;
60  }
61 
65  @Override
68  AvailableNetwork network = new AvailableNetwork(driver, flow.isIgnoreBandwidth(), flow.getBandwidth());
69  return getPath(flow, network, strategy);
70  }
71 
75  @Override
78 
79  long latency = 0L;
80  List<PathNode> forwardNodes = new LinkedList<>();
81  List<PathNode> reverseNodes = new LinkedList<>();
82 
83  if (!flow.isOneSwitchFlow()) {
84  try {
85  Pair<LinkedList<SimpleIsl>, LinkedList<SimpleIsl>> biPath = getPathFromNetwork(flow, network, strategy);
86  if (biPath.getLeft().size() == 0 || biPath.getRight().size() == 0) {
87  throw new UnroutablePathException(flow);
88  }
89 
90  int seqId = 0;
91  LinkedList<SimpleIsl> forwardIsl = biPath.getLeft();
92  for (SimpleIsl isl : forwardIsl) {
93  latency += isl.getLatency();
94  forwardNodes.add(new PathNode(isl.getSrcDpid(), isl.getSrcPort(),
95  seqId++, (long) isl.getLatency()));
96  forwardNodes.add(new PathNode(isl.getDstDpid(), isl.getDstPort(), seqId++, 0L));
97  }
98 
99  seqId = 0;
100  LinkedList<SimpleIsl> reverseIsl = biPath.getRight();
101  for (SimpleIsl isl : reverseIsl) {
102  reverseNodes.add(new PathNode(isl.getSrcDpid(), isl.getSrcPort(),
103  seqId++, (long) isl.getLatency()));
104  reverseNodes.add(new PathNode(isl.getDstDpid(), isl.getDstPort(), seqId++, 0L));
105  }
106  // FIXME(surabujin): Need to catch and trace exact exception thrown in recoverable places.
107  } catch (TransientException e) {
108  throw new RecoverableException("TransientError from neo4j", e);
109  } catch (ClientException e) {
110  throw new RecoverableException("ClientException from neo4j", e);
111  }
112  } else {
113  logger.info("No path computation for one-switch flow");
114  }
115 
116  return new ImmutablePair<>(new PathInfoData(latency, forwardNodes), new PathInfoData(latency, reverseNodes));
117  }
118 
122  private Pair<LinkedList<SimpleIsl>, LinkedList<SimpleIsl>> getPathFromNetwork(Flow flow, AvailableNetwork network,
123  Strategy strategy) {
124 
125  switch (strategy) {
126  default:
127  network.removeSelfLoops().reduceByCost();
128  SimpleGetShortestPath forward = new SimpleGetShortestPath(network,
129  flow.getSourceSwitch(), flow.getDestinationSwitch(), 35);
130  SimpleGetShortestPath reverse = new SimpleGetShortestPath(network,
131  flow.getDestinationSwitch(), flow.getSourceSwitch(), 35);
132 
133  LinkedList<SimpleIsl> forwardPath = forward.getPath();
134  LinkedList<SimpleIsl> reversePath = reverse.getPath(forwardPath);
135  //(crimi) - getPath with hint works .. you can use the next line to troubleshoot if
136  // concerned about how hit is working
137  //LinkedList<SimpleIsl> rPath = reverse.getPath();
138  Pair<LinkedList<SimpleIsl>, LinkedList<SimpleIsl>> path = Pair.of(forwardPath, reversePath);
139  return path;
140  }
141  }
142 
143 
147  @Override
148  public List<FlowInfo> getFlowInfo() {
149  List<FlowInfo> flows = new ArrayList<>();
150  String subject = "MATCH (:switch)-[f:flow]->(:switch) "
151  + "RETURN f.flowid as flow_id, "
152  + " f.cookie as cookie, "
153  + " f.meter_id as meter_id, "
154  + " f.transit_vlan as transit_vlan, "
155  + " f.src_switch as src_switch";
156 
157  try (Session session = driver.session(AccessMode.READ)) {
158  StatementResult result = session.run(subject);
159 
160  for (Record record : result.list()) {
161  flows.add(new FlowInfo()
162  .setFlowId(record.get("flow_id").asString())
163  .setSrcSwitchId(record.get("src_switch").asString())
164  .setCookie(record.get("cookie").asLong())
165  .setMeterId(safeAsInt(record.get("meter_id")))
166  .setTransitVlanId(safeAsInt(record.get("transit_vlan")))
167  );
168  }
169 
170  }
171  return flows;
172  }
173 
174  @Override
175  public List<Flow> getFlow(String flowId) {
176  List<Flow> found = getFlows(flowId);
177  return found.size() > 0 ? found : null;
178  }
179 
180  @Override
181  public List<Flow> getFlows(String flowId) {
182  String where = "WHERE f.flowid= $flow_id ";
183  Value parameters = Values.parameters("flow_id", flowId);
184  return loadFlows(where, parameters);
185  }
186 
187  @Override
188  public List<Flow> getAllFlows() {
189  String noWhere = " ";
190  return loadFlows(noWhere, null);
191  }
192 
193 
194  private List<Flow> loadFlows(String whereClause, Value parameters) {
195  String q =
196  "MATCH (:switch)-[f:flow]->(:switch) "
197  + whereClause
198  + "RETURN f.flowid as flowid, "
199  + "f.bandwidth as bandwidth, "
200  + "f.ignore_bandwidth as ignore_bandwidth, "
201  + "f.cookie as cookie, "
202  + "f.description as description, "
203  + "f.last_updated as last_updated, "
204  + "f.src_switch as src_switch, "
205  + "f.dst_switch as dst_switch, "
206  + "f.src_port as src_port, "
207  + "f.dst_port as dst_port, "
208  + "f.src_vlan as src_vlan, "
209  + "f.dst_vlan as dst_vlan, "
210  + "f.flowpath as path, "
211  + "f.meter_id as meter_id, "
212  + "f.transit_vlan as transit_vlan";
213 
214  logger.debug("Executing getFlows Query: {}", q);
215 
216  try (Session session = driver.session(AccessMode.READ)) {
217  StatementResult queryResults = session.run(q, parameters);
218  List<Flow> results = new ArrayList<>();
219  for (Record record : queryResults.list()) {
220  FlowAdapter adapter = new FlowAdapter(record);
221  results.add(adapter.getFlow());
222  }
223  return results;
224  }
225  }
226 
227  @Override
228  public List<SwitchInfoData> getSwitches() {
229  String q =
230  "MATCH (sw:switch) "
231  + "RETURN "
232  + "sw.name as name, "
233  + "sw.address as address, "
234  + "sw.hostname as hostname, "
235  + "sw.description as description, "
236  + "sw.controller as controller, "
237  + "sw.state as state "
238  + "order by sw.name";
239  logger.debug("Executing getSwitches Query: {}", q);
240 
241  List<SwitchInfoData> results = new LinkedList<>();
242  try (Session session = driver.session(AccessMode.READ)) {
243  StatementResult queryResults = session.run(q);
244  for (Record record : queryResults.list()) {
245  SwitchInfoData sw = new SwitchInfoData();
246  sw.setAddress(record.get("address").asString());
247  sw.setController(record.get("controller").asString());
248  sw.setDescription(record.get("description").asString());
249  sw.setHostname(record.get("hostname").asString());
250 
251  String status = record.get("state").asString();
252  SwitchState st = ("active".equals(status)) ? SwitchState.ACTIVATED : SwitchState.CACHED;
253  sw.setState(st);
254 
255  sw.setSwitchId(new SwitchId(record.get("name").asString()));
256  results.add(sw);
257  }
258  }
259  return results;
260  }
261 
262  @Override
263  public List<IslInfoData> getIsls() {
264 
265  String q =
266  "MATCH (:switch)-[isl:isl]->(:switch) "
267  + "RETURN "
268  + "isl.src_switch as src_switch, "
269  + "isl.src_port as src_port, "
270  + "isl.dst_switch as dst_switch, "
271  + "isl.dst_port as dst_port, "
272  + "isl.speed as speed, "
273  + "isl.max_bandwidth as max_bandwidth, "
274  + "isl.latency as latency, "
275  + "isl.available_bandwidth as available_bandwidth, "
276  + "isl.status as status "
277  + "order by isl.src_switch";
278 
279  logger.debug("Executing getSwitches Query: {}", q);
280  try (Session session = driver.session(AccessMode.READ)) {
281 
282  StatementResult queryResults = session.run(q);
283  List<IslInfoData> results = new LinkedList<>();
284  for (Record record : queryResults.list()) {
285  // max_bandwidth not used in IslInfoData
286  PathNode src = new PathNode();
287  src.setSwitchId(new SwitchId(record.get("src_switch").asString()));
288  src.setPortNo(safeAsInt(record.get("src_port")));
289  src.setSegLatency(safeAsInt(record.get("latency")));
290 
291  List<PathNode> pathNodes = new ArrayList<>();
292  pathNodes.add(src);
293 
294  PathNode dst = new PathNode();
295  dst.setSwitchId(new SwitchId(record.get("dst_switch").asString()));
296  dst.setPortNo(safeAsInt(record.get("dst_port")));
297  dst.setSegLatency(safeAsInt(record.get("latency")));
298  pathNodes.add(dst);
299 
300  String status = record.get("status").asString();
301  IslChangeType state = ("active".equals(status)) ? IslChangeType.DISCOVERED : IslChangeType.FAILED;
302 
303  IslInfoData isl = new IslInfoData(
304  safeAsInt(record.get("latency")),
305  pathNodes,
306  safeAsInt(record.get("speed")),
307  state,
308  safeAsInt(record.get("available_bandwidth"))
309  );
310  isl.setTimestamp(System.currentTimeMillis());
311 
312  results.add(isl);
313  }
314  return results;
315  }
316  }
317 
318  @Override
319  public AvailableNetwork getAvailableNetwork(boolean ignoreBandwidth, long requestedBandwidth) {
320  return new AvailableNetwork(driver, ignoreBandwidth, requestedBandwidth);
321  }
322 }
void setTimestamp(long timestamp)
List< Flow > getFlow(String flowId)
Definition: NeoDriver.java:175
List< Flow > getFlows(String flowId)
Definition: NeoDriver.java:181
ImmutablePair< PathInfoData, PathInfoData > getPath(Flow flow, Strategy strategy)
Definition: NeoDriver.java:66
List< SwitchInfoData > getSwitches()
Definition: NeoDriver.java:228
def status()
Definition: rest.py:593
void setSegLatency(final long latency)
Definition: PathNode.java:207
void setSwitchId(final SwitchId switchId)
Definition: PathNode.java:147
list result
Definition: plan-d.py:72
ImmutablePair< PathInfoData, PathInfoData > getPath(Flow flow, AvailableNetwork network, Strategy strategy)
Definition: NeoDriver.java:76
static int safeAsInt(Value val)
Definition: Utils.java:43
AvailableNetwork getAvailableNetwork(boolean ignoreBandwidth, long requestedBandwidth)
Definition: NeoDriver.java:319
FlowInfo setTransitVlanId(int transitVlanId)
Definition: FlowInfo.java:48