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