blob: 9c3192417fef938de644a52fdf2d268e1b6fd465 [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08006import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.HashMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.Map;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.concurrent.Executors;
11import java.util.concurrent.ScheduledExecutorService;
12import java.util.concurrent.ScheduledFuture;
13import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IFloodlightProviderService;
16import net.floodlightcontroller.core.INetMapStorage;
17import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
18import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
19import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020import net.floodlightcontroller.core.module.FloodlightModuleContext;
21import net.floodlightcontroller.core.module.FloodlightModuleException;
22import net.floodlightcontroller.core.module.IFloodlightModule;
23import net.floodlightcontroller.core.module.IFloodlightService;
24import net.floodlightcontroller.flowcache.IFlowService;
25import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
26import net.floodlightcontroller.restserver.IRestApiService;
27import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080028import net.floodlightcontroller.util.DataPath;
29import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080030import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080031import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070032import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070034import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035import net.floodlightcontroller.util.FlowEntrySwitchState;
36import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080037import net.floodlightcontroller.util.FlowId;
38import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070039import net.floodlightcontroller.util.IPv4Net;
40import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.OFMessageDamper;
42import net.floodlightcontroller.util.Port;
43import net.onrc.onos.util.GraphDBConnection;
44import net.onrc.onos.util.GraphDBConnection.Transaction;
45
46import org.openflow.protocol.OFFlowMod;
47import org.openflow.protocol.OFMatch;
48import org.openflow.protocol.OFPacketOut;
49import org.openflow.protocol.OFType;
50import org.openflow.protocol.action.OFAction;
51import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080052
53import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
55
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
57
58 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059
60 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080061 protected IFloodlightProviderService floodlightProvider;
62
63 protected OFMessageDamper messageDamper;
64
65 protected static int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
66 protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
67 public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
68 public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080069
70 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
72
73 // The periodic task(s)
74 private final ScheduledExecutorService scheduler =
75 Executors.newScheduledThreadPool(1);
76 final Runnable reader = new Runnable() {
77 public void run() {
78 // log.debug("Reading Flow Entries from the Network Map...");
79 if (floodlightProvider == null) {
80 log.debug("FloodlightProvider service not found!");
81 return;
82 }
83
84 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
85
86 // Fetch all Flow Entries
87 Iterable<IFlowEntry> flowEntries = conn.utils().getAllFlowEntries(conn);
88 for (IFlowEntry flowEntryObj : flowEntries) {
89 FlowEntryId flowEntryId =
90 new FlowEntryId(flowEntryObj.getFlowEntryId());
91 String userState = flowEntryObj.getUserState();
92 String switchState = flowEntryObj.getSwitchState();
93
94 log.debug("Found Flow Entry {}: ", flowEntryId.toString());
95 log.debug("User State {}:", userState);
96 log.debug("Switch State {}:", switchState);
97
98 if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
99 // Ignore the entry: nothing to do
100 continue;
101 }
102
103 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
104 IOFSwitch mySwitch = mySwitches.get(dpid.value());
105 if (mySwitch == null) {
106 log.debug("Flow Entry ignored: not my switch");
107 continue;
108 }
109
110 //
111 // Create the Open Flow Flow Modification Entry to push
112 //
113 OFFlowMod fm =
114 (OFFlowMod) floodlightProvider.getOFMessageFactory()
115 .getMessage(OFType.FLOW_MOD);
116 long cookie = flowEntryId.value();
117
118 short flowModCommand = OFFlowMod.OFPFC_ADD;
119 if (userState.equals("FE_USER_ADD")) {
120 flowModCommand = OFFlowMod.OFPFC_ADD;
121 } else if (userState.equals("FE_USER_MODIFY")) {
122 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
123 } else if (userState.equals("FE_USER_DELETE")) {
124 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
125 } else {
126 // Unknown user state. Ignore the entry
127 continue;
128 }
129
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700130 //
131 // Fetch the match conditions
132 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800133 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700134 match.setWildcards(OFMatch.OFPFW_ALL);
135 Short matchInPort = flowEntryObj.getMatchInPort();
136 if (matchInPort != null) {
137 match.setInputPort(matchInPort);
138 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
139 }
140 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
141 if (matchEthernetFrameType != null) {
142 match.setDataLayerType(matchEthernetFrameType);
143 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
144 }
145 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
146 if (matchSrcIPv4Net != null) {
147 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
148 }
149 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
150 if (matchDstIPv4Net != null) {
151 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
152 }
153 String matchSrcMac = flowEntryObj.getMatchSrcMac();
154 if (matchSrcMac != null) {
155 match.setDataLayerSource(matchSrcMac);
156 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
157 }
158 String matchDstMac = flowEntryObj.getMatchDstMac();
159 if (matchDstMac != null) {
160 match.setDataLayerDestination(matchDstMac);
161 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
162 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700163
164 //
165 // Fetch the actions
166 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800167 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700168 Short actionOutputPort = flowEntryObj.getActionOutput();
169 if (actionOutputPort != null) {
170 OFActionOutput action = new OFActionOutput();
171 // XXX: The max length is hard-coded for now
172 action.setMaxLength((short)0xffff);
173 action.setPort(actionOutputPort);
174 actions.add(action);
175 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800176
177 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
178 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
179 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
180 .setCookie(cookie)
181 .setCommand(flowModCommand)
182 .setMatch(match)
183 .setActions(actions)
184 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
185 //
186 // TODO: Set the following flag
187 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
188 // See method ForwardingBase::pushRoute()
189 //
190 try {
191 messageDamper.write(mySwitch, fm, null);
192 mySwitch.flush();
193 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
194 if (userState.equals("FE_USER_DELETE")) {
195 // Delete the entry
196 IFlowPath flowObj = null;
197 flowObj = conn.utils().getFlowPathByFlowEntry(conn,
198 flowEntryObj);
199 if (flowObj != null)
200 log.debug("Found FlowPath to be deleted");
201 else
202 log.debug("Did not find FlowPath to be deleted");
203 flowObj.removeFlowEntry(flowEntryObj);
204 conn.utils().removeFlowEntry(conn, flowEntryObj);
205
206 // Test whether the last flow entry
207 Iterable<IFlowEntry> tmpflowEntries =
208 flowObj.getFlowEntries();
209 boolean found = false;
210 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
211 found = true;
212 break;
213 }
214 if (! found) {
215 // Remove the Flow Path as well
216 conn.utils().removeFlowPath(conn, flowObj);
217 }
218 }
219 } catch (IOException e) {
220 log.error("Failure writing flow mod from network map", e);
221 }
222 }
223 conn.endTx(Transaction.COMMIT);
224 }
225 };
226 final ScheduledFuture<?> readerHandle =
227 scheduler.scheduleAtFixedRate(reader, 3, 3, TimeUnit.SECONDS);
228
229 @Override
230 public void init(String conf) {
231 conn = GraphDBConnection.getInstance(conf);
232 }
233
234 public void finalize() {
235 close();
236 }
237
238 @Override
239 public void close() {
240 conn.close();
241 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800242
243 @Override
244 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
245 Collection<Class<? extends IFloodlightService>> l =
246 new ArrayList<Class<? extends IFloodlightService>>();
247 l.add(IFlowService.class);
248 return l;
249 }
250
251 @Override
252 public Map<Class<? extends IFloodlightService>, IFloodlightService>
253 getServiceImpls() {
254 Map<Class<? extends IFloodlightService>,
255 IFloodlightService> m =
256 new HashMap<Class<? extends IFloodlightService>,
257 IFloodlightService>();
258 m.put(IFlowService.class, this);
259 return m;
260 }
261
262 @Override
263 public Collection<Class<? extends IFloodlightService>>
264 getModuleDependencies() {
265 Collection<Class<? extends IFloodlightService>> l =
266 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800267 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800268 l.add(IRestApiService.class);
269 return l;
270 }
271
272 @Override
273 public void init(FloodlightModuleContext context)
274 throws FloodlightModuleException {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800275 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800276 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800277 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
278 EnumSet.of(OFType.FLOW_MOD),
279 OFMESSAGE_DAMPER_TIMEOUT);
280 // TODO: An ugly hack!
281 String conf = "/tmp/cassandra.titan";
282 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800283 }
284
285 @Override
286 public void startUp(FloodlightModuleContext context) {
287 restApi.addRestletRoutable(new FlowWebRoutable());
288 }
289
290 /**
291 * Add a flow.
292 *
293 * Internally, ONOS will automatically register the installer for
294 * receiving Flow Path Notifications for that path.
295 *
296 * @param flowPath the Flow Path to install.
297 * @param flowId the return-by-reference Flow ID as assigned internally.
298 * @return true on success, otherwise false.
299 */
300 @Override
301 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800302
303 //
304 // Assign the FlowEntry IDs
305 // TODO: This is an ugly hack!
306 // The Flow Entry IDs are set to 1000*FlowId + Index
307 //
308 int i = 1;
309 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
310 long id = flowPath.flowId().value() * 1000 + i;
311 ++i;
312 flowEntry.setFlowEntryId(new FlowEntryId(id));
313 }
314
315 IFlowPath flowObj = null;
316 try {
317 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
318 != null) {
319 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
320 flowPath.flowId().toString());
321 } else {
322 flowObj = conn.utils().newFlowPath(conn);
323 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
324 flowPath.flowId().toString());
325 }
326 } catch (Exception e) {
327 // TODO: handle exceptions
328 conn.endTx(Transaction.ROLLBACK);
329 log.error(":addFlow FlowId:{} failed",
330 flowPath.flowId().toString());
331 }
332 if (flowObj == null)
333 return false;
334
335 //
336 // Set the Flow key:
337 // - flowId
338 //
339 flowObj.setFlowId(flowPath.flowId().toString());
340 flowObj.setType("flow");
341
342 //
343 // Set the Flow attributes:
344 // - flowPath.installerId()
345 // - flowPath.dataPath().srcPort()
346 // - flowPath.dataPath().dstPort()
347 //
348 flowObj.setInstallerId(flowPath.installerId().toString());
349 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
350 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
351 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
352 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
353
354 // Flow edges:
355 // HeadFE
356
357
358 //
359 // Flow Entries:
360 // flowPath.dataPath().flowEntries()
361 //
362 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
363 IFlowEntry flowEntryObj = null;
364 boolean found = false;
365 try {
366 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
367 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
368 flowEntry.flowEntryId().toString());
369 found = true;
370 } else {
371 flowEntryObj = conn.utils().newFlowEntry(conn);
372 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
373 flowEntry.flowEntryId().toString());
374 }
375 } catch (Exception e) {
376 // TODO: handle exceptions
377 conn.endTx(Transaction.ROLLBACK);
378 log.error(":addFlow FlowEntryId:{} failed",
379 flowEntry.flowEntryId().toString());
380 }
381 if (flowEntryObj == null)
382 return false;
383
384 //
385 // Set the Flow Entry key:
386 // - flowEntry.flowEntryId()
387 //
388 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
389 flowEntryObj.setType("flow_entry");
390
391 //
392 // Set the Flow Entry attributes:
393 // - flowEntry.flowEntryMatch()
394 // - flowEntry.flowEntryActions()
395 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800396 // - flowEntry.flowEntryUserState()
397 // - flowEntry.flowEntrySwitchState()
398 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700399 // - flowEntry.matchInPort()
400 // - flowEntry.matchEthernetFrameType()
401 // - flowEntry.matchSrcIPv4Net()
402 // - flowEntry.matchDstIPv4Net()
403 // - flowEntry.matchSrcMac()
404 // - flowEntry.matchDstMac()
405 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800406 //
407 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700408 if (flowEntry.flowEntryMatch().matchInPort())
409 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
410 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
411 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
412 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
413 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
414 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
415 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
416 if (flowEntry.flowEntryMatch().matchSrcMac())
417 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
418 if (flowEntry.flowEntryMatch().matchDstMac())
419 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
420
421 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
422 if (fa.actionOutput() != null)
423 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
424 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800425 // TODO: Hacks with hard-coded state names!
426 if (found)
427 flowEntryObj.setUserState("FE_USER_MODIFY");
428 else
429 flowEntryObj.setUserState("FE_USER_ADD");
430 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
431 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800432 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800433 // and FlowEntryErrorState.
434 //
435
436 // Flow Entries edges:
437 // Flow
438 // NextFE
439 // InPort
440 // OutPort
441 // Switch
442 if (! found)
443 flowObj.addFlowEntry(flowEntryObj);
444 }
445 conn.endTx(Transaction.COMMIT);
446
447 //
448 // TODO: We need a proper Flow ID allocation mechanism.
449 //
450 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800451 return true;
452 }
453
454 /**
455 * Delete a previously added flow.
456 *
457 * @param flowId the Flow ID of the flow to delete.
458 * @return true on success, otherwise false.
459 */
460 @Override
461 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800462 IFlowPath flowObj = null;
463 //
464 // We just mark the entries for deletion,
465 // and let the switches remove each individual entry after
466 // it has been removed from the switches.
467 //
468 try {
469 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
470 != null) {
471 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
472 flowId.toString());
473 } else {
474 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
475 flowId.toString());
476 }
477 } catch (Exception e) {
478 // TODO: handle exceptions
479 conn.endTx(Transaction.ROLLBACK);
480 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
481 }
482 if (flowObj == null)
483 return true; // OK: No such flow
484
485 //
486 // Find and mark for deletion all Flow Entries
487 //
488 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
489 boolean empty = true; // TODO: an ugly hack
490 for (IFlowEntry flowEntryObj : flowEntries) {
491 empty = false;
492 // flowObj.removeFlowEntry(flowEntryObj);
493 // conn.utils().removeFlowEntry(conn, flowEntryObj);
494 flowEntryObj.setUserState("FE_USER_DELETE");
495 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
496 }
497 // Remove from the database empty flows
498 if (empty)
499 conn.utils().removeFlowPath(conn, flowObj);
500 conn.endTx(Transaction.COMMIT);
501
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800502 return true;
503 }
504
505 /**
506 * Get a previously added flow.
507 *
508 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800509 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800510 */
511 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800512 public FlowPath getFlow(FlowId flowId) {
513 IFlowPath flowObj = null;
514 try {
515 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
516 != null) {
517 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
518 flowId.toString());
519 } else {
520 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
521 flowId.toString());
522 }
523 } catch (Exception e) {
524 // TODO: handle exceptions
525 conn.endTx(Transaction.ROLLBACK);
526 log.error(":getFlow FlowId:{} failed", flowId.toString());
527 }
528 if (flowObj == null)
529 return null; // Flow not found
530
531 //
532 // Extract the Flow state
533 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800534 FlowPath flowPath = extractFlowPath(flowObj);
535 conn.endTx(Transaction.COMMIT);
536
537 return flowPath;
538 }
539
540 /**
541 * Get all previously added flows by a specific installer for a given
542 * data path endpoints.
543 *
544 * @param installerId the Caller ID of the installer of the flow to get.
545 * @param dataPathEndpoints the data path endpoints of the flow to get.
546 * @return the Flow Paths if found, otherwise null.
547 */
548 @Override
549 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
550 DataPathEndpoints dataPathEndpoints) {
551 //
552 // TODO: The implementation below is not optimal:
553 // We fetch all flows, and then return only the subset that match
554 // the query conditions.
555 // We should use the appropriate Titan/Gremlin query to filter-out
556 // the flows as appropriate.
557 //
558 ArrayList<FlowPath> allFlows = getAllFlows();
559
560 if (allFlows == null) {
561 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
562 return null;
563 }
564
565 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
566 for (FlowPath flow : allFlows) {
567 //
568 // TODO: String-based comparison is sub-optimal.
569 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800570 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800571 //
572 if (! flow.installerId().toString().equals(installerId.toString()))
573 continue;
574 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
575 continue;
576 }
577 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
578 continue;
579 }
580 flowPaths.add(flow);
581 }
582
583 if (flowPaths.isEmpty()) {
584 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
585 flowPaths = null;
586 } else {
587 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
588 }
589
590 return flowPaths;
591 }
592
593 /**
594 * Get all installed flows by all installers for given data path endpoints.
595 *
596 * @param dataPathEndpoints the data path endpoints of the flows to get.
597 * @return the Flow Paths if found, otherwise null.
598 */
599 @Override
600 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
601 //
602 // TODO: The implementation below is not optimal:
603 // We fetch all flows, and then return only the subset that match
604 // the query conditions.
605 // We should use the appropriate Titan/Gremlin query to filter-out
606 // the flows as appropriate.
607 //
608 ArrayList<FlowPath> allFlows = getAllFlows();
609
610 if (allFlows == null) {
611 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
612 return null;
613 }
614
615 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
616 for (FlowPath flow : allFlows) {
617 //
618 // TODO: String-based comparison is sub-optimal.
619 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800620 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800621 //
622 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
623 continue;
624 }
625 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
626 continue;
627 }
628 flowPaths.add(flow);
629 }
630
631 if (flowPaths.isEmpty()) {
632 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
633 flowPaths = null;
634 } else {
635 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
636 }
637
638 return flowPaths;
639 }
640
641 /**
642 * Get all installed flows by all installers.
643 *
644 * @return the Flow Paths if found, otherwise null.
645 */
646 @Override
647 public ArrayList<FlowPath> getAllFlows() {
648 Iterable<IFlowPath> flowPathsObj = null;
649
650 try {
651 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
652 log.debug("Get all FlowPaths: found FlowPaths");
653 } else {
654 log.debug("Get all FlowPaths: no FlowPaths found");
655 }
656 } catch (Exception e) {
657 // TODO: handle exceptions
658 conn.endTx(Transaction.ROLLBACK);
659 log.error(":getAllFlowPaths failed");
660 }
661 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false))
662 return null; // No Flows found
663
664 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
665 for (IFlowPath flowObj : flowPathsObj) {
666 //
667 // Extract the Flow state
668 //
669 FlowPath flowPath = extractFlowPath(flowObj);
670 flowPaths.add(flowPath);
671 }
672
673 conn.endTx(Transaction.COMMIT);
674
675 return flowPaths;
676 }
677
678 /**
679 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
680 *
681 * @param flowObj the object to extract the Flow Path State from.
682 * @return the extracted Flow Path State.
683 */
684 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800685 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800686
687 //
688 // Extract the Flow state
689 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800690 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
691 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
692 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
693 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
694 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
695 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
696
697 //
698 // Extract all Flow Entries
699 //
700 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
701 for (IFlowEntry flowEntryObj : flowEntries) {
702 FlowEntry flowEntry = new FlowEntry();
703 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
704 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700705
706 //
707 // Extract the match conditions
708 //
709 FlowEntryMatch match = new FlowEntryMatch();
710 Short matchInPort = flowEntryObj.getMatchInPort();
711 if (matchInPort != null)
712 match.enableInPort(new Port(matchInPort));
713 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
714 if (matchEthernetFrameType != null)
715 match.enableEthernetFrameType(matchEthernetFrameType);
716 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
717 if (matchSrcIPv4Net != null)
718 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
719 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
720 if (matchDstIPv4Net != null)
721 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
722 String matchSrcMac = flowEntryObj.getMatchSrcMac();
723 if (matchSrcMac != null)
724 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
725 String matchDstMac = flowEntryObj.getMatchDstMac();
726 if (matchDstMac != null)
727 match.enableDstMac(MACAddress.valueOf(matchDstMac));
728 flowEntry.setFlowEntryMatch(match);
729
730 //
731 // Extract the actions
732 //
733 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
734 Short actionOutputPort = flowEntryObj.getActionOutput();
735 if (actionOutputPort != null) {
736 FlowEntryAction action = new FlowEntryAction();
737 action.setActionOutput(new Port(actionOutputPort));
738 actions.add(action);
739 }
740 flowEntry.setFlowEntryActions(actions);
741
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800742 String userState = flowEntryObj.getUserState();
743 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
744 String switchState = flowEntryObj.getSwitchState();
745 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
746 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800747 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800748 // and FlowEntryErrorState.
749 //
750 flowPath.dataPath().flowEntries().add(flowEntry);
751 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800752
753 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800754 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800755}