blob: 74cfcbe7faf30a45d968961aac5e1edc648b9d7f [file] [log] [blame]
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -07001package net.onrc.onos.ofcontroller.flowmanager;
2
3import java.io.PrintWriter;
4import java.io.StringWriter;
5import java.util.ArrayList;
6import java.util.Collections;
7import java.util.Comparator;
8import java.util.LinkedList;
9import java.util.List;
10import java.util.concurrent.ConcurrentLinkedQueue;
11
12import net.floodlightcontroller.util.MACAddress;
13
14import net.onrc.onos.graph.GraphDBOperation;
15
16import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
17import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
18import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
19import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
20import net.onrc.onos.ofcontroller.util.*;
21
22import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
24
25/**
26 * Class for performing Flow-related operations on the Database.
27 */
28class FlowDatabaseOperation {
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070029 private final static Logger log = LoggerFactory.getLogger(FlowDatabaseOperation.class);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070030
31 /**
32 * Add a flow.
33 *
34 * @param flowManager the Flow Manager to use.
35 * @param dbHandler the Graph Database handler to use.
36 * @param flowPath the Flow Path to install.
37 * @param flowId the return-by-reference Flow ID as assigned internally.
38 * @param dataPathSummaryStr the data path summary string if the added
39 * flow will be maintained internally, otherwise null.
40 * @return true on success, otherwise false.
41 */
42 static boolean addFlow(FlowManager flowManager,
43 GraphDBOperation dbHandler,
44 FlowPath flowPath, FlowId flowId,
45 String dataPathSummaryStr) {
46 IFlowPath flowObj = null;
47 boolean found = false;
48 try {
49 if ((flowObj = dbHandler.searchFlowPath(flowPath.flowId())) != null) {
50 found = true;
51 } else {
52 flowObj = dbHandler.newFlowPath();
53 }
54 } catch (Exception e) {
55 dbHandler.rollback();
56
57 StringWriter sw = new StringWriter();
58 e.printStackTrace(new PrintWriter(sw));
59 String stacktrace = sw.toString();
60
61 log.error(":addFlow FlowId:{} failed: {}",
62 flowPath.flowId().toString(),
63 stacktrace);
64 return false;
65 }
66 if (flowObj == null) {
67 log.error(":addFlow FlowId:{} failed: Flow object not created",
68 flowPath.flowId().toString());
69 dbHandler.rollback();
70 return false;
71 }
72
73 //
74 // Set the Flow key:
75 // - flowId
76 //
77 flowObj.setFlowId(flowPath.flowId().toString());
78 flowObj.setType("flow");
79
80 //
81 // Set the Flow attributes:
82 // - flowPath.installerId()
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -070083 // - flowPath.flowPathType()
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070084 // - flowPath.flowPathFlags()
85 // - flowPath.dataPath().srcPort()
86 // - flowPath.dataPath().dstPort()
87 // - flowPath.matchSrcMac()
88 // - flowPath.matchDstMac()
89 // - flowPath.matchEthernetFrameType()
90 // - flowPath.matchVlanId()
91 // - flowPath.matchVlanPriority()
92 // - flowPath.matchSrcIPv4Net()
93 // - flowPath.matchDstIPv4Net()
94 // - flowPath.matchIpProto()
95 // - flowPath.matchIpToS()
96 // - flowPath.matchSrcTcpUdpPort()
97 // - flowPath.matchDstTcpUdpPort()
98 // - flowPath.flowEntryActions()
99 //
100 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700101 flowObj.setFlowPathType(flowPath.flowPathType().toString());
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700102 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
103 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
104 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
105 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
106 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
107 if (flowPath.flowEntryMatch().matchSrcMac()) {
108 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
109 }
110 if (flowPath.flowEntryMatch().matchDstMac()) {
111 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
112 }
113 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
114 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
115 }
116 if (flowPath.flowEntryMatch().matchVlanId()) {
117 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
118 }
119 if (flowPath.flowEntryMatch().matchVlanPriority()) {
120 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
121 }
122 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
123 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
124 }
125 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
126 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
127 }
128 if (flowPath.flowEntryMatch().matchIpProto()) {
129 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
130 }
131 if (flowPath.flowEntryMatch().matchIpToS()) {
132 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
133 }
134 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
135 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
136 }
137 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
138 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
139 }
140 if (! flowPath.flowEntryActions().actions().isEmpty()) {
141 flowObj.setActions(flowPath.flowEntryActions().toString());
142 }
143
144 if (dataPathSummaryStr != null) {
145 flowObj.setDataPathSummary(dataPathSummaryStr);
146 } else {
147 flowObj.setDataPathSummary("");
148 }
149
150 if (found)
151 flowObj.setUserState("FE_USER_MODIFY");
152 else
153 flowObj.setUserState("FE_USER_ADD");
154
155 // Flow edges:
156 // HeadFE
157
158
159 //
160 // Flow Entries:
161 // flowPath.dataPath().flowEntries()
162 //
163 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
164 if (addFlowEntry(flowManager, dbHandler, flowObj, flowEntry) == null) {
165 dbHandler.rollback();
166 return false;
167 }
168 }
169 dbHandler.commit();
170
171 //
172 // TODO: We need a proper Flow ID allocation mechanism.
173 //
174 flowId.setValue(flowPath.flowId().value());
175
176 return true;
177 }
178
179 /**
180 * Add a flow entry to the Network MAP.
181 *
182 * @param flowManager the Flow Manager to use.
183 * @param dbHandler the Graph Database handler to use.
184 * @param flowObj the corresponding Flow Path object for the Flow Entry.
185 * @param flowEntry the Flow Entry to install.
186 * @return the added Flow Entry object on success, otherwise null.
187 */
188 static IFlowEntry addFlowEntry(FlowManager flowManager,
189 GraphDBOperation dbHandler,
190 IFlowPath flowObj,
191 FlowEntry flowEntry) {
192 // Flow edges
193 // HeadFE (TODO)
194
195 //
196 // Assign the FlowEntry ID.
197 //
198 if ((flowEntry.flowEntryId() == null) ||
199 (flowEntry.flowEntryId().value() == 0)) {
200 long id = flowManager.getNextFlowEntryId();
201 flowEntry.setFlowEntryId(new FlowEntryId(id));
202 }
203
204 IFlowEntry flowEntryObj = null;
205 boolean found = false;
206 try {
207 if ((flowEntryObj =
208 dbHandler.searchFlowEntry(flowEntry.flowEntryId())) != null) {
209 found = true;
210 } else {
211 flowEntryObj = dbHandler.newFlowEntry();
212 }
213 } catch (Exception e) {
214 log.error(":addFlow FlowEntryId:{} failed",
215 flowEntry.flowEntryId().toString());
216 return null;
217 }
218 if (flowEntryObj == null) {
219 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
220 flowEntry.flowEntryId().toString());
221 return null;
222 }
223
224 //
225 // Set the Flow Entry key:
226 // - flowEntry.flowEntryId()
227 //
228 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
229 flowEntryObj.setType("flow_entry");
230
231 //
232 // Set the Flow Entry Edges and attributes:
233 // - Switch edge
234 // - InPort edge
235 // - OutPort edge
236 //
237 // - flowEntry.dpid()
238 // - flowEntry.flowEntryUserState()
239 // - flowEntry.flowEntrySwitchState()
240 // - flowEntry.flowEntryErrorState()
241 // - flowEntry.matchInPort()
242 // - flowEntry.matchSrcMac()
243 // - flowEntry.matchDstMac()
244 // - flowEntry.matchEthernetFrameType()
245 // - flowEntry.matchVlanId()
246 // - flowEntry.matchVlanPriority()
247 // - flowEntry.matchSrcIPv4Net()
248 // - flowEntry.matchDstIPv4Net()
249 // - flowEntry.matchIpProto()
250 // - flowEntry.matchIpToS()
251 // - flowEntry.matchSrcTcpUdpPort()
252 // - flowEntry.matchDstTcpUdpPort()
253 // - flowEntry.actionOutputPort()
254 // - flowEntry.actions()
255 //
256 ISwitchObject sw = dbHandler.searchSwitch(flowEntry.dpid().toString());
257 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
258 flowEntryObj.setSwitch(sw);
259 if (flowEntry.flowEntryMatch().matchInPort()) {
260 IPortObject inport =
261 dbHandler.searchPort(flowEntry.dpid().toString(),
262 flowEntry.flowEntryMatch().inPort().value());
263 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
264 flowEntryObj.setInPort(inport);
265 }
266 if (flowEntry.flowEntryMatch().matchSrcMac()) {
267 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
268 }
269 if (flowEntry.flowEntryMatch().matchDstMac()) {
270 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
271 }
272 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
273 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
274 }
275 if (flowEntry.flowEntryMatch().matchVlanId()) {
276 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
277 }
278 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
279 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
280 }
281 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
282 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
283 }
284 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
285 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
286 }
287 if (flowEntry.flowEntryMatch().matchIpProto()) {
288 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
289 }
290 if (flowEntry.flowEntryMatch().matchIpToS()) {
291 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
292 }
293 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
294 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
295 }
296 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
297 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
298 }
299
300 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
301 if (fa.actionOutput() != null) {
302 IPortObject outport =
303 dbHandler.searchPort(flowEntry.dpid().toString(),
304 fa.actionOutput().port().value());
305 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
306 flowEntryObj.setOutPort(outport);
307 }
308 }
309 if (! flowEntry.flowEntryActions().isEmpty()) {
310 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
311 }
312
313 // TODO: Hacks with hard-coded state names!
314 if (found)
315 flowEntryObj.setUserState("FE_USER_MODIFY");
316 else
317 flowEntryObj.setUserState("FE_USER_ADD");
318 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
319 //
320 // TODO: Take care of the FlowEntryErrorState.
321 //
322
323 // Flow Entries edges:
324 // Flow
325 // NextFE (TODO)
326 if (! found) {
327 flowObj.addFlowEntry(flowEntryObj);
328 flowEntryObj.setFlow(flowObj);
329 }
330
331 return flowEntryObj;
332 }
333
334 /**
335 * Delete all previously added flows.
336 *
337 * @param dbHandler the Graph Database handler to use.
338 * @return true on success, otherwise false.
339 */
340 static boolean deleteAllFlows(GraphDBOperation dbHandler) {
341 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
342 new ConcurrentLinkedQueue<FlowId>();
343
344 // Get all Flow IDs
345 Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
346 for (IFlowPath flowPathObj : allFlowPaths) {
347 if (flowPathObj == null)
348 continue;
349 String flowIdStr = flowPathObj.getFlowId();
350 if (flowIdStr == null)
351 continue;
352 FlowId flowId = new FlowId(flowIdStr);
353 concurrentAllFlowIds.add(flowId);
354 }
355
356 // Delete all flows one-by-one
357 for (FlowId flowId : concurrentAllFlowIds)
358 deleteFlow(dbHandler, flowId);
359
360 /*
361 * TODO: A faster mechanism to delete the Flow Paths by using
362 * a number of threads. Commented-out for now.
363 */
364 /*
365 //
366 // Create the threads to delete the Flow Paths
367 //
368 List<Thread> threads = new LinkedList<Thread>();
369 for (int i = 0; i < 10; i++) {
370 Thread thread = new Thread(new Runnable() {
371 @Override
372 public void run() {
373 while (true) {
374 FlowId flowId = concurrentAllFlowIds.poll();
375 if (flowId == null)
376 return;
377 deleteFlow(dbHandler, flowId);
378 }
379 }}, "Delete All Flow Paths");
380 threads.add(thread);
381 }
382
383 // Start processing
384 for (Thread thread : threads) {
385 thread.start();
386 }
387
388 // Wait for all threads to complete
389 for (Thread thread : threads) {
390 try {
391 thread.join();
392 } catch (InterruptedException e) {
393 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
394 }
395 }
396 */
397
398 return true;
399 }
400
401 /**
402 * Delete a previously added flow.
403 *
404 * @param dbHandler the Graph Database handler to use.
405 * @param flowId the Flow ID of the flow to delete.
406 * @return true on success, otherwise false.
407 */
408 static boolean deleteFlow(GraphDBOperation dbHandler, FlowId flowId) {
409 IFlowPath flowObj = null;
410 //
411 // We just mark the entries for deletion,
412 // and let the switches remove each individual entry after
413 // it has been removed from the switches.
414 //
415 try {
416 flowObj = dbHandler.searchFlowPath(flowId);
417 } catch (Exception e) {
418 // TODO: handle exceptions
419 dbHandler.rollback();
420 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
421 return false;
422 }
423 if (flowObj == null) {
424 dbHandler.commit();
425 return true; // OK: No such flow
426 }
427
428 //
429 // Find and mark for deletion all Flow Entries,
430 // and the Flow itself.
431 //
432 flowObj.setUserState("FE_USER_DELETE");
433 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
434 boolean empty = true; // TODO: an ugly hack
435 for (IFlowEntry flowEntryObj : flowEntries) {
436 empty = false;
437 // flowObj.removeFlowEntry(flowEntryObj);
438 // conn.utils().removeFlowEntry(conn, flowEntryObj);
439 flowEntryObj.setUserState("FE_USER_DELETE");
440 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
441 }
442 // Remove from the database empty flows
443 if (empty)
444 dbHandler.removeFlowPath(flowObj);
445 dbHandler.commit();
446
447 return true;
448 }
449
450 /**
451 * Clear the state for all previously added flows.
452 *
453 * @param dbHandler the Graph Database handler to use.
454 * @return true on success, otherwise false.
455 */
456 static boolean clearAllFlows(GraphDBOperation dbHandler) {
457 List<FlowId> allFlowIds = new LinkedList<FlowId>();
458
459 // Get all Flow IDs
460 Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
461 for (IFlowPath flowPathObj : allFlowPaths) {
462 if (flowPathObj == null)
463 continue;
464 String flowIdStr = flowPathObj.getFlowId();
465 if (flowIdStr == null)
466 continue;
467 FlowId flowId = new FlowId(flowIdStr);
468 allFlowIds.add(flowId);
469 }
470
471 // Clear all flows one-by-one
472 for (FlowId flowId : allFlowIds) {
473 clearFlow(dbHandler, flowId);
474 }
475
476 return true;
477 }
478
479 /**
480 * Clear the state for a previously added flow.
481 *
482 * @param dbHandler the Graph Database handler to use.
483 * @param flowId the Flow ID of the flow to clear.
484 * @return true on success, otherwise false.
485 */
486 static boolean clearFlow(GraphDBOperation dbHandler, FlowId flowId) {
487 IFlowPath flowObj = null;
488 try {
489 flowObj = dbHandler.searchFlowPath(flowId);
490 } catch (Exception e) {
491 // TODO: handle exceptions
492 dbHandler.rollback();
493 log.error(":clearFlow FlowId:{} failed", flowId.toString());
494 return false;
495 }
496 if (flowObj == null) {
497 dbHandler.commit();
498 return true; // OK: No such flow
499 }
500
501 //
502 // Remove all Flow Entries
503 //
504 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
505 for (IFlowEntry flowEntryObj : flowEntries) {
506 flowObj.removeFlowEntry(flowEntryObj);
507 dbHandler.removeFlowEntry(flowEntryObj);
508 }
509 // Remove the Flow itself
510 dbHandler.removeFlowPath(flowObj);
511 dbHandler.commit();
512
513 return true;
514 }
515
516 /**
517 * Get a previously added flow.
518 *
519 * @param dbHandler the Graph Database handler to use.
520 * @param flowId the Flow ID of the flow to get.
521 * @return the Flow Path if found, otherwise null.
522 */
523 static FlowPath getFlow(GraphDBOperation dbHandler, FlowId flowId) {
524 IFlowPath flowObj = null;
525 try {
526 flowObj = dbHandler.searchFlowPath(flowId);
527 } catch (Exception e) {
528 // TODO: handle exceptions
529 dbHandler.rollback();
530 log.error(":getFlow FlowId:{} failed", flowId.toString());
531 return null;
532 }
533 if (flowObj == null) {
534 dbHandler.commit();
535 return null; // Flow not found
536 }
537
538 //
539 // Extract the Flow state
540 //
541 FlowPath flowPath = extractFlowPath(flowObj);
542 dbHandler.commit();
543
544 return flowPath;
545 }
546
547 /**
548 * Get all installed flows by all installers.
549 *
550 * @param dbHandler the Graph Database handler to use.
551 * @return the Flow Paths if found, otherwise null.
552 */
553 static ArrayList<FlowPath> getAllFlows(GraphDBOperation dbHandler) {
554 Iterable<IFlowPath> flowPathsObj = null;
555 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
556
557 try {
558 flowPathsObj = dbHandler.getAllFlowPaths();
559 } catch (Exception e) {
560 // TODO: handle exceptions
561 dbHandler.rollback();
562 log.error(":getAllFlowPaths failed");
563 return flowPaths;
564 }
565 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
566 dbHandler.commit();
567 return flowPaths; // No Flows found
568 }
569
570 for (IFlowPath flowObj : flowPathsObj) {
571 //
572 // Extract the Flow state
573 //
574 FlowPath flowPath = extractFlowPath(flowObj);
575 if (flowPath != null)
576 flowPaths.add(flowPath);
577 }
578
579 dbHandler.commit();
580
581 return flowPaths;
582 }
583
584 /**
585 * Get all previously added flows by a specific installer for a given
586 * data path endpoints.
587 *
588 * @param dbHandler the Graph Database handler to use.
589 * @param installerId the Caller ID of the installer of the flow to get.
590 * @param dataPathEndpoints the data path endpoints of the flow to get.
591 * @return the Flow Paths if found, otherwise null.
592 */
593 static ArrayList<FlowPath> getAllFlows(GraphDBOperation dbHandler,
594 CallerId installerId,
595 DataPathEndpoints dataPathEndpoints) {
596 //
597 // TODO: The implementation below is not optimal:
598 // We fetch all flows, and then return only the subset that match
599 // the query conditions.
600 // We should use the appropriate Titan/Gremlin query to filter-out
601 // the flows as appropriate.
602 //
603 ArrayList<FlowPath> allFlows = getAllFlows(dbHandler);
604 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
605
606 if (allFlows == null)
607 return flowPaths;
608
609 for (FlowPath flow : allFlows) {
610 //
611 // TODO: String-based comparison is sub-optimal.
612 // We are using it for now to save us the extra work of
613 // implementing the "equals()" and "hashCode()" methods.
614 //
615 if (! flow.installerId().toString().equals(installerId.toString()))
616 continue;
617 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
618 continue;
619 }
620 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
621 continue;
622 }
623 flowPaths.add(flow);
624 }
625
626 return flowPaths;
627 }
628
629 /**
630 * Get all installed flows by all installers for given data path endpoints.
631 *
632 * @param dbHandler the Graph Database handler to use.
633 * @param dataPathEndpoints the data path endpoints of the flows to get.
634 * @return the Flow Paths if found, otherwise null.
635 */
636 static ArrayList<FlowPath> getAllFlows(GraphDBOperation dbHandler,
637 DataPathEndpoints dataPathEndpoints) {
638 //
639 // TODO: The implementation below is not optimal:
640 // We fetch all flows, and then return only the subset that match
641 // the query conditions.
642 // We should use the appropriate Titan/Gremlin query to filter-out
643 // the flows as appropriate.
644 //
645 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
646 ArrayList<FlowPath> allFlows = getAllFlows(dbHandler);
647
648 if (allFlows == null)
649 return flowPaths;
650
651 for (FlowPath flow : allFlows) {
652 //
653 // TODO: String-based comparison is sub-optimal.
654 // We are using it for now to save us the extra work of
655 // implementing the "equals()" and "hashCode()" methods.
656 //
657 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
658 continue;
659 }
660 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
661 continue;
662 }
663 flowPaths.add(flow);
664 }
665
666 return flowPaths;
667 }
668
669 /**
670 * Get summary of all installed flows by all installers in a given range.
671 *
672 * @param dbHandler the Graph Database handler to use.
673 * @param flowId the Flow ID of the first flow in the flow range to get.
674 * @param maxFlows the maximum number of flows to be returned.
675 * @return the Flow Paths if found, otherwise null.
676 */
677 static ArrayList<IFlowPath> getAllFlowsSummary(GraphDBOperation dbHandler,
678 FlowId flowId,
679 int maxFlows) {
680 //
681 // TODO: The implementation below is not optimal:
682 // We fetch all flows, and then return only the subset that match
683 // the query conditions.
684 // We should use the appropriate Titan/Gremlin query to filter-out
685 // the flows as appropriate.
686 //
687 ArrayList<IFlowPath> flowPathsWithoutFlowEntries =
688 getAllFlowsWithoutFlowEntries(dbHandler);
689
690 Collections.sort(flowPathsWithoutFlowEntries,
691 new Comparator<IFlowPath>() {
692 @Override
693 public int compare(IFlowPath first, IFlowPath second) {
694 long result =
695 new FlowId(first.getFlowId()).value()
696 - new FlowId(second.getFlowId()).value();
697 if (result > 0) {
698 return 1;
699 } else if (result < 0) {
700 return -1;
701 } else {
702 return 0;
703 }
704 }
705 }
706 );
707
708 return flowPathsWithoutFlowEntries;
709 }
710
711 /**
712 * Get all Flows information, without the associated Flow Entries.
713 *
714 * @param dbHandler the Graph Database handler to use.
715 * @return all Flows information, without the associated Flow Entries.
716 */
717 static ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(GraphDBOperation dbHandler) {
718 Iterable<IFlowPath> flowPathsObj = null;
719 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
720
721 // TODO: Remove this op.commit() flow, because it is not needed?
722 dbHandler.commit();
723
724 try {
725 flowPathsObj = dbHandler.getAllFlowPaths();
726 } catch (Exception e) {
727 // TODO: handle exceptions
728 dbHandler.rollback();
729 log.error(":getAllFlowPaths failed");
730 return flowPathsObjArray; // No Flows found
731 }
732 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
733 return flowPathsObjArray; // No Flows found
734 }
735
736 for (IFlowPath flowObj : flowPathsObj)
737 flowPathsObjArray.add(flowObj);
738
739 // conn.endTx(Transaction.COMMIT);
740
741 return flowPathsObjArray;
742 }
743
744 /**
745 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
746 *
747 * @param flowObj the object to extract the Flow Path State from.
748 * @return the extracted Flow Path State.
749 */
750 private static FlowPath extractFlowPath(IFlowPath flowObj) {
751 //
752 // Extract the Flow state
753 //
754 String flowIdStr = flowObj.getFlowId();
755 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700756 String flowPathType = flowObj.getFlowPathType();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700757 Long flowPathFlags = flowObj.getFlowPathFlags();
758 String srcSwitchStr = flowObj.getSrcSwitch();
759 Short srcPortShort = flowObj.getSrcPort();
760 String dstSwitchStr = flowObj.getDstSwitch();
761 Short dstPortShort = flowObj.getDstPort();
762
763 if ((flowIdStr == null) ||
764 (installerIdStr == null) ||
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700765 (flowPathType == null) ||
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700766 (flowPathFlags == null) ||
767 (srcSwitchStr == null) ||
768 (srcPortShort == null) ||
769 (dstSwitchStr == null) ||
770 (dstPortShort == null)) {
771 // TODO: A work-around, becauuse of some bogus database objects
772 return null;
773 }
774
775 FlowPath flowPath = new FlowPath();
776 flowPath.setFlowId(new FlowId(flowIdStr));
777 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavovd28cf7c2013-10-26 11:27:43 -0700778 flowPath.setFlowPathType(FlowPathType.valueOf(flowPathType));
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700779 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
780 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
781 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
782 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
783 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
784 //
785 // Extract the match conditions common for all Flow Entries
786 //
787 {
788 FlowEntryMatch match = new FlowEntryMatch();
789 String matchSrcMac = flowObj.getMatchSrcMac();
790 if (matchSrcMac != null)
791 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
792 String matchDstMac = flowObj.getMatchDstMac();
793 if (matchDstMac != null)
794 match.enableDstMac(MACAddress.valueOf(matchDstMac));
795 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
796 if (matchEthernetFrameType != null)
797 match.enableEthernetFrameType(matchEthernetFrameType);
798 Short matchVlanId = flowObj.getMatchVlanId();
799 if (matchVlanId != null)
800 match.enableVlanId(matchVlanId);
801 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
802 if (matchVlanPriority != null)
803 match.enableVlanPriority(matchVlanPriority);
804 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
805 if (matchSrcIPv4Net != null)
806 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
807 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
808 if (matchDstIPv4Net != null)
809 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
810 Byte matchIpProto = flowObj.getMatchIpProto();
811 if (matchIpProto != null)
812 match.enableIpProto(matchIpProto);
813 Byte matchIpToS = flowObj.getMatchIpToS();
814 if (matchIpToS != null)
815 match.enableIpToS(matchIpToS);
816 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
817 if (matchSrcTcpUdpPort != null)
818 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
819 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
820 if (matchDstTcpUdpPort != null)
821 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
822
823 flowPath.setFlowEntryMatch(match);
824 }
825 //
826 // Extract the actions for the first Flow Entry
827 //
828 {
829 String actionsStr = flowObj.getActions();
830 if (actionsStr != null) {
831 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
832 flowPath.setFlowEntryActions(flowEntryActions);
833 }
834 }
835
836 //
837 // Extract all Flow Entries
838 //
839 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
840 for (IFlowEntry flowEntryObj : flowEntries) {
841 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
842 if (flowEntry == null)
843 continue;
844 flowPath.dataPath().flowEntries().add(flowEntry);
845 }
846
847 return flowPath;
848 }
849
850 /**
851 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
852 *
853 * @param flowEntryObj the object to extract the Flow Entry State from.
854 * @return the extracted Flow Entry State.
855 */
856 private static FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
857 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
858 String switchDpidStr = flowEntryObj.getSwitchDpid();
859 String userState = flowEntryObj.getUserState();
860 String switchState = flowEntryObj.getSwitchState();
861
862 if ((flowEntryIdStr == null) ||
863 (switchDpidStr == null) ||
864 (userState == null) ||
865 (switchState == null)) {
866 // TODO: A work-around, becauuse of some bogus database objects
867 return null;
868 }
869
870 FlowEntry flowEntry = new FlowEntry();
871 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
872 flowEntry.setDpid(new Dpid(switchDpidStr));
873
874 //
875 // Extract the match conditions
876 //
877 FlowEntryMatch match = new FlowEntryMatch();
878 Short matchInPort = flowEntryObj.getMatchInPort();
879 if (matchInPort != null)
880 match.enableInPort(new Port(matchInPort));
881 String matchSrcMac = flowEntryObj.getMatchSrcMac();
882 if (matchSrcMac != null)
883 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
884 String matchDstMac = flowEntryObj.getMatchDstMac();
885 if (matchDstMac != null)
886 match.enableDstMac(MACAddress.valueOf(matchDstMac));
887 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
888 if (matchEthernetFrameType != null)
889 match.enableEthernetFrameType(matchEthernetFrameType);
890 Short matchVlanId = flowEntryObj.getMatchVlanId();
891 if (matchVlanId != null)
892 match.enableVlanId(matchVlanId);
893 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
894 if (matchVlanPriority != null)
895 match.enableVlanPriority(matchVlanPriority);
896 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
897 if (matchSrcIPv4Net != null)
898 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
899 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
900 if (matchDstIPv4Net != null)
901 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
902 Byte matchIpProto = flowEntryObj.getMatchIpProto();
903 if (matchIpProto != null)
904 match.enableIpProto(matchIpProto);
905 Byte matchIpToS = flowEntryObj.getMatchIpToS();
906 if (matchIpToS != null)
907 match.enableIpToS(matchIpToS);
908 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
909 if (matchSrcTcpUdpPort != null)
910 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
911 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
912 if (matchDstTcpUdpPort != null)
913 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
914 flowEntry.setFlowEntryMatch(match);
915
916 //
917 // Extract the actions
918 //
919 FlowEntryActions actions = new FlowEntryActions();
920 String actionsStr = flowEntryObj.getActions();
921 if (actionsStr != null)
922 actions = new FlowEntryActions(actionsStr);
923 flowEntry.setFlowEntryActions(actions);
924 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
925 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
926 //
927 // TODO: Take care of FlowEntryErrorState.
928 //
929 return flowEntry;
930 }
931}