blob: 838c3ed6781fbc1daf2c4b0171b78da0510f8d25 [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 }
163 log.debug("PAVPAV {}:", match.toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800164
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700165
166 //
167 // Fetch the actions
168 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800169 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700170 Short actionOutputPort = flowEntryObj.getActionOutput();
171 if (actionOutputPort != null) {
172 OFActionOutput action = new OFActionOutput();
173 // XXX: The max length is hard-coded for now
174 action.setMaxLength((short)0xffff);
175 action.setPort(actionOutputPort);
176 actions.add(action);
177 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800178
179 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
180 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
181 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
182 .setCookie(cookie)
183 .setCommand(flowModCommand)
184 .setMatch(match)
185 .setActions(actions)
186 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
187 //
188 // TODO: Set the following flag
189 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
190 // See method ForwardingBase::pushRoute()
191 //
192 try {
193 messageDamper.write(mySwitch, fm, null);
194 mySwitch.flush();
195 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
196 if (userState.equals("FE_USER_DELETE")) {
197 // Delete the entry
198 IFlowPath flowObj = null;
199 flowObj = conn.utils().getFlowPathByFlowEntry(conn,
200 flowEntryObj);
201 if (flowObj != null)
202 log.debug("Found FlowPath to be deleted");
203 else
204 log.debug("Did not find FlowPath to be deleted");
205 flowObj.removeFlowEntry(flowEntryObj);
206 conn.utils().removeFlowEntry(conn, flowEntryObj);
207
208 // Test whether the last flow entry
209 Iterable<IFlowEntry> tmpflowEntries =
210 flowObj.getFlowEntries();
211 boolean found = false;
212 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
213 found = true;
214 break;
215 }
216 if (! found) {
217 // Remove the Flow Path as well
218 conn.utils().removeFlowPath(conn, flowObj);
219 }
220 }
221 } catch (IOException e) {
222 log.error("Failure writing flow mod from network map", e);
223 }
224 }
225 conn.endTx(Transaction.COMMIT);
226 }
227 };
228 final ScheduledFuture<?> readerHandle =
229 scheduler.scheduleAtFixedRate(reader, 3, 3, TimeUnit.SECONDS);
230
231 @Override
232 public void init(String conf) {
233 conn = GraphDBConnection.getInstance(conf);
234 }
235
236 public void finalize() {
237 close();
238 }
239
240 @Override
241 public void close() {
242 conn.close();
243 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800244
245 @Override
246 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
247 Collection<Class<? extends IFloodlightService>> l =
248 new ArrayList<Class<? extends IFloodlightService>>();
249 l.add(IFlowService.class);
250 return l;
251 }
252
253 @Override
254 public Map<Class<? extends IFloodlightService>, IFloodlightService>
255 getServiceImpls() {
256 Map<Class<? extends IFloodlightService>,
257 IFloodlightService> m =
258 new HashMap<Class<? extends IFloodlightService>,
259 IFloodlightService>();
260 m.put(IFlowService.class, this);
261 return m;
262 }
263
264 @Override
265 public Collection<Class<? extends IFloodlightService>>
266 getModuleDependencies() {
267 Collection<Class<? extends IFloodlightService>> l =
268 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800269 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800270 l.add(IRestApiService.class);
271 return l;
272 }
273
274 @Override
275 public void init(FloodlightModuleContext context)
276 throws FloodlightModuleException {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800277 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800278 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800279 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
280 EnumSet.of(OFType.FLOW_MOD),
281 OFMESSAGE_DAMPER_TIMEOUT);
282 // TODO: An ugly hack!
283 String conf = "/tmp/cassandra.titan";
284 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800285 }
286
287 @Override
288 public void startUp(FloodlightModuleContext context) {
289 restApi.addRestletRoutable(new FlowWebRoutable());
290 }
291
292 /**
293 * Add a flow.
294 *
295 * Internally, ONOS will automatically register the installer for
296 * receiving Flow Path Notifications for that path.
297 *
298 * @param flowPath the Flow Path to install.
299 * @param flowId the return-by-reference Flow ID as assigned internally.
300 * @return true on success, otherwise false.
301 */
302 @Override
303 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800304
305 //
306 // Assign the FlowEntry IDs
307 // TODO: This is an ugly hack!
308 // The Flow Entry IDs are set to 1000*FlowId + Index
309 //
310 int i = 1;
311 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
312 long id = flowPath.flowId().value() * 1000 + i;
313 ++i;
314 flowEntry.setFlowEntryId(new FlowEntryId(id));
315 }
316
317 IFlowPath flowObj = null;
318 try {
319 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
320 != null) {
321 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
322 flowPath.flowId().toString());
323 } else {
324 flowObj = conn.utils().newFlowPath(conn);
325 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
326 flowPath.flowId().toString());
327 }
328 } catch (Exception e) {
329 // TODO: handle exceptions
330 conn.endTx(Transaction.ROLLBACK);
331 log.error(":addFlow FlowId:{} failed",
332 flowPath.flowId().toString());
333 }
334 if (flowObj == null)
335 return false;
336
337 //
338 // Set the Flow key:
339 // - flowId
340 //
341 flowObj.setFlowId(flowPath.flowId().toString());
342 flowObj.setType("flow");
343
344 //
345 // Set the Flow attributes:
346 // - flowPath.installerId()
347 // - flowPath.dataPath().srcPort()
348 // - flowPath.dataPath().dstPort()
349 //
350 flowObj.setInstallerId(flowPath.installerId().toString());
351 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
352 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
353 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
354 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
355
356 // Flow edges:
357 // HeadFE
358
359
360 //
361 // Flow Entries:
362 // flowPath.dataPath().flowEntries()
363 //
364 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
365 IFlowEntry flowEntryObj = null;
366 boolean found = false;
367 try {
368 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
369 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
370 flowEntry.flowEntryId().toString());
371 found = true;
372 } else {
373 flowEntryObj = conn.utils().newFlowEntry(conn);
374 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
375 flowEntry.flowEntryId().toString());
376 }
377 } catch (Exception e) {
378 // TODO: handle exceptions
379 conn.endTx(Transaction.ROLLBACK);
380 log.error(":addFlow FlowEntryId:{} failed",
381 flowEntry.flowEntryId().toString());
382 }
383 if (flowEntryObj == null)
384 return false;
385
386 //
387 // Set the Flow Entry key:
388 // - flowEntry.flowEntryId()
389 //
390 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
391 flowEntryObj.setType("flow_entry");
392
393 //
394 // Set the Flow Entry attributes:
395 // - flowEntry.flowEntryMatch()
396 // - flowEntry.flowEntryActions()
397 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800398 // - flowEntry.flowEntryUserState()
399 // - flowEntry.flowEntrySwitchState()
400 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700401 // - flowEntry.matchInPort()
402 // - flowEntry.matchEthernetFrameType()
403 // - flowEntry.matchSrcIPv4Net()
404 // - flowEntry.matchDstIPv4Net()
405 // - flowEntry.matchSrcMac()
406 // - flowEntry.matchDstMac()
407 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800408 //
409 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700410 if (flowEntry.flowEntryMatch().matchInPort())
411 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
412 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
413 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
414 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
415 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
416 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
417 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
418 if (flowEntry.flowEntryMatch().matchSrcMac())
419 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
420 if (flowEntry.flowEntryMatch().matchDstMac())
421 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
422
423 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
424 if (fa.actionOutput() != null)
425 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
426 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800427 // TODO: Hacks with hard-coded state names!
428 if (found)
429 flowEntryObj.setUserState("FE_USER_MODIFY");
430 else
431 flowEntryObj.setUserState("FE_USER_ADD");
432 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
433 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800434 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800435 // and FlowEntryErrorState.
436 //
437
438 // Flow Entries edges:
439 // Flow
440 // NextFE
441 // InPort
442 // OutPort
443 // Switch
444 if (! found)
445 flowObj.addFlowEntry(flowEntryObj);
446 }
447 conn.endTx(Transaction.COMMIT);
448
449 //
450 // TODO: We need a proper Flow ID allocation mechanism.
451 //
452 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800453 return true;
454 }
455
456 /**
457 * Delete a previously added flow.
458 *
459 * @param flowId the Flow ID of the flow to delete.
460 * @return true on success, otherwise false.
461 */
462 @Override
463 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800464 IFlowPath flowObj = null;
465 //
466 // We just mark the entries for deletion,
467 // and let the switches remove each individual entry after
468 // it has been removed from the switches.
469 //
470 try {
471 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
472 != null) {
473 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
474 flowId.toString());
475 } else {
476 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
477 flowId.toString());
478 }
479 } catch (Exception e) {
480 // TODO: handle exceptions
481 conn.endTx(Transaction.ROLLBACK);
482 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
483 }
484 if (flowObj == null)
485 return true; // OK: No such flow
486
487 //
488 // Find and mark for deletion all Flow Entries
489 //
490 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
491 boolean empty = true; // TODO: an ugly hack
492 for (IFlowEntry flowEntryObj : flowEntries) {
493 empty = false;
494 // flowObj.removeFlowEntry(flowEntryObj);
495 // conn.utils().removeFlowEntry(conn, flowEntryObj);
496 flowEntryObj.setUserState("FE_USER_DELETE");
497 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
498 }
499 // Remove from the database empty flows
500 if (empty)
501 conn.utils().removeFlowPath(conn, flowObj);
502 conn.endTx(Transaction.COMMIT);
503
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800504 return true;
505 }
506
507 /**
508 * Get a previously added flow.
509 *
510 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800511 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800512 */
513 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800514 public FlowPath getFlow(FlowId flowId) {
515 IFlowPath flowObj = null;
516 try {
517 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
518 != null) {
519 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
520 flowId.toString());
521 } else {
522 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
523 flowId.toString());
524 }
525 } catch (Exception e) {
526 // TODO: handle exceptions
527 conn.endTx(Transaction.ROLLBACK);
528 log.error(":getFlow FlowId:{} failed", flowId.toString());
529 }
530 if (flowObj == null)
531 return null; // Flow not found
532
533 //
534 // Extract the Flow state
535 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800536 FlowPath flowPath = extractFlowPath(flowObj);
537 conn.endTx(Transaction.COMMIT);
538
539 return flowPath;
540 }
541
542 /**
543 * Get all previously added flows by a specific installer for a given
544 * data path endpoints.
545 *
546 * @param installerId the Caller ID of the installer of the flow to get.
547 * @param dataPathEndpoints the data path endpoints of the flow to get.
548 * @return the Flow Paths if found, otherwise null.
549 */
550 @Override
551 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
552 DataPathEndpoints dataPathEndpoints) {
553 //
554 // TODO: The implementation below is not optimal:
555 // We fetch all flows, and then return only the subset that match
556 // the query conditions.
557 // We should use the appropriate Titan/Gremlin query to filter-out
558 // the flows as appropriate.
559 //
560 ArrayList<FlowPath> allFlows = getAllFlows();
561
562 if (allFlows == null) {
563 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
564 return null;
565 }
566
567 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
568 for (FlowPath flow : allFlows) {
569 //
570 // TODO: String-based comparison is sub-optimal.
571 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800572 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800573 //
574 if (! flow.installerId().toString().equals(installerId.toString()))
575 continue;
576 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
577 continue;
578 }
579 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
580 continue;
581 }
582 flowPaths.add(flow);
583 }
584
585 if (flowPaths.isEmpty()) {
586 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
587 flowPaths = null;
588 } else {
589 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
590 }
591
592 return flowPaths;
593 }
594
595 /**
596 * Get all installed flows by all installers for given data path endpoints.
597 *
598 * @param dataPathEndpoints the data path endpoints of the flows to get.
599 * @return the Flow Paths if found, otherwise null.
600 */
601 @Override
602 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
603 //
604 // TODO: The implementation below is not optimal:
605 // We fetch all flows, and then return only the subset that match
606 // the query conditions.
607 // We should use the appropriate Titan/Gremlin query to filter-out
608 // the flows as appropriate.
609 //
610 ArrayList<FlowPath> allFlows = getAllFlows();
611
612 if (allFlows == null) {
613 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
614 return null;
615 }
616
617 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
618 for (FlowPath flow : allFlows) {
619 //
620 // TODO: String-based comparison is sub-optimal.
621 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800622 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800623 //
624 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
625 continue;
626 }
627 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
628 continue;
629 }
630 flowPaths.add(flow);
631 }
632
633 if (flowPaths.isEmpty()) {
634 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
635 flowPaths = null;
636 } else {
637 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
638 }
639
640 return flowPaths;
641 }
642
643 /**
644 * Get all installed flows by all installers.
645 *
646 * @return the Flow Paths if found, otherwise null.
647 */
648 @Override
649 public ArrayList<FlowPath> getAllFlows() {
650 Iterable<IFlowPath> flowPathsObj = null;
651
652 try {
653 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
654 log.debug("Get all FlowPaths: found FlowPaths");
655 } else {
656 log.debug("Get all FlowPaths: no FlowPaths found");
657 }
658 } catch (Exception e) {
659 // TODO: handle exceptions
660 conn.endTx(Transaction.ROLLBACK);
661 log.error(":getAllFlowPaths failed");
662 }
663 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false))
664 return null; // No Flows found
665
666 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
667 for (IFlowPath flowObj : flowPathsObj) {
668 //
669 // Extract the Flow state
670 //
671 FlowPath flowPath = extractFlowPath(flowObj);
672 flowPaths.add(flowPath);
673 }
674
675 conn.endTx(Transaction.COMMIT);
676
677 return flowPaths;
678 }
679
680 /**
681 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
682 *
683 * @param flowObj the object to extract the Flow Path State from.
684 * @return the extracted Flow Path State.
685 */
686 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800687 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800688
689 //
690 // Extract the Flow state
691 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800692 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
693 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
694 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
695 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
696 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
697 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
698
699 //
700 // Extract all Flow Entries
701 //
702 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
703 for (IFlowEntry flowEntryObj : flowEntries) {
704 FlowEntry flowEntry = new FlowEntry();
705 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
706 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700707
708 //
709 // Extract the match conditions
710 //
711 FlowEntryMatch match = new FlowEntryMatch();
712 Short matchInPort = flowEntryObj.getMatchInPort();
713 if (matchInPort != null)
714 match.enableInPort(new Port(matchInPort));
715 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
716 if (matchEthernetFrameType != null)
717 match.enableEthernetFrameType(matchEthernetFrameType);
718 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
719 if (matchSrcIPv4Net != null)
720 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
721 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
722 if (matchDstIPv4Net != null)
723 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
724 String matchSrcMac = flowEntryObj.getMatchSrcMac();
725 if (matchSrcMac != null)
726 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
727 String matchDstMac = flowEntryObj.getMatchDstMac();
728 if (matchDstMac != null)
729 match.enableDstMac(MACAddress.valueOf(matchDstMac));
730 flowEntry.setFlowEntryMatch(match);
731
732 //
733 // Extract the actions
734 //
735 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
736 Short actionOutputPort = flowEntryObj.getActionOutput();
737 if (actionOutputPort != null) {
738 FlowEntryAction action = new FlowEntryAction();
739 action.setActionOutput(new Port(actionOutputPort));
740 actions.add(action);
741 }
742 flowEntry.setFlowEntryActions(actions);
743
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800744 String userState = flowEntryObj.getUserState();
745 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
746 String switchState = flowEntryObj.getSwitchState();
747 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
748 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800749 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800750 // and FlowEntryErrorState.
751 //
752 flowPath.dataPath().flowEntries().add(flowEntry);
753 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800754
755 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800756 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800757}