blob: a6049695e13242e3962fe6df001b430a7bf9ad76 [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;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070049import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080050import org.openflow.protocol.OFType;
51import org.openflow.protocol.action.OFAction;
52import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080053
54import org.slf4j.Logger;
55import org.slf4j.LoggerFactory;
56
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
58
59 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080060
61 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062 protected IFloodlightProviderService floodlightProvider;
63
64 protected OFMessageDamper messageDamper;
65
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070066 //
67 // TODO: Values copied from elsewhere (class LearningSwitch).
68 // The local copy should go away!
69 //
70 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
71 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
72 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
73 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
74 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080075
76 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
78
79 // The periodic task(s)
80 private final ScheduledExecutorService scheduler =
81 Executors.newScheduledThreadPool(1);
82 final Runnable reader = new Runnable() {
83 public void run() {
84 // log.debug("Reading Flow Entries from the Network Map...");
85 if (floodlightProvider == null) {
86 log.debug("FloodlightProvider service not found!");
87 return;
88 }
89
90 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
91
92 // Fetch all Flow Entries
93 Iterable<IFlowEntry> flowEntries = conn.utils().getAllFlowEntries(conn);
94 for (IFlowEntry flowEntryObj : flowEntries) {
95 FlowEntryId flowEntryId =
96 new FlowEntryId(flowEntryObj.getFlowEntryId());
97 String userState = flowEntryObj.getUserState();
98 String switchState = flowEntryObj.getSwitchState();
99
100 log.debug("Found Flow Entry {}: ", flowEntryId.toString());
101 log.debug("User State {}:", userState);
102 log.debug("Switch State {}:", switchState);
103
104 if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
105 // Ignore the entry: nothing to do
106 continue;
107 }
108
109 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
110 IOFSwitch mySwitch = mySwitches.get(dpid.value());
111 if (mySwitch == null) {
112 log.debug("Flow Entry ignored: not my switch");
113 continue;
114 }
115
116 //
117 // Create the Open Flow Flow Modification Entry to push
118 //
119 OFFlowMod fm =
120 (OFFlowMod) floodlightProvider.getOFMessageFactory()
121 .getMessage(OFType.FLOW_MOD);
122 long cookie = flowEntryId.value();
123
124 short flowModCommand = OFFlowMod.OFPFC_ADD;
125 if (userState.equals("FE_USER_ADD")) {
126 flowModCommand = OFFlowMod.OFPFC_ADD;
127 } else if (userState.equals("FE_USER_MODIFY")) {
128 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
129 } else if (userState.equals("FE_USER_DELETE")) {
130 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
131 } else {
132 // Unknown user state. Ignore the entry
133 continue;
134 }
135
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700136 //
137 // Fetch the match conditions
138 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800139 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700140 match.setWildcards(OFMatch.OFPFW_ALL);
141 Short matchInPort = flowEntryObj.getMatchInPort();
142 if (matchInPort != null) {
143 match.setInputPort(matchInPort);
144 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
145 }
146 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
147 if (matchEthernetFrameType != null) {
148 match.setDataLayerType(matchEthernetFrameType);
149 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
150 }
151 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
152 if (matchSrcIPv4Net != null) {
153 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
154 }
155 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
156 if (matchDstIPv4Net != null) {
157 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
158 }
159 String matchSrcMac = flowEntryObj.getMatchSrcMac();
160 if (matchSrcMac != null) {
161 match.setDataLayerSource(matchSrcMac);
162 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
163 }
164 String matchDstMac = flowEntryObj.getMatchDstMac();
165 if (matchDstMac != null) {
166 match.setDataLayerDestination(matchDstMac);
167 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
168 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700169
170 //
171 // Fetch the actions
172 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800173 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700174 Short actionOutputPort = flowEntryObj.getActionOutput();
175 if (actionOutputPort != null) {
176 OFActionOutput action = new OFActionOutput();
177 // XXX: The max length is hard-coded for now
178 action.setMaxLength((short)0xffff);
179 action.setPort(actionOutputPort);
180 actions.add(action);
181 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800182
183 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
184 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700185 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800186 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
187 .setCookie(cookie)
188 .setCommand(flowModCommand)
189 .setMatch(match)
190 .setActions(actions)
191 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700192 fm.setOutPort(OFPort.OFPP_NONE.getValue());
193 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
194 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
195 if (actionOutputPort != null)
196 fm.setOutPort(actionOutputPort);
197 }
198
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800199 //
200 // TODO: Set the following flag
201 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
202 // See method ForwardingBase::pushRoute()
203 //
204 try {
205 messageDamper.write(mySwitch, fm, null);
206 mySwitch.flush();
207 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
208 if (userState.equals("FE_USER_DELETE")) {
209 // Delete the entry
210 IFlowPath flowObj = null;
211 flowObj = conn.utils().getFlowPathByFlowEntry(conn,
212 flowEntryObj);
213 if (flowObj != null)
214 log.debug("Found FlowPath to be deleted");
215 else
216 log.debug("Did not find FlowPath to be deleted");
217 flowObj.removeFlowEntry(flowEntryObj);
218 conn.utils().removeFlowEntry(conn, flowEntryObj);
219
220 // Test whether the last flow entry
221 Iterable<IFlowEntry> tmpflowEntries =
222 flowObj.getFlowEntries();
223 boolean found = false;
224 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
225 found = true;
226 break;
227 }
228 if (! found) {
229 // Remove the Flow Path as well
230 conn.utils().removeFlowPath(conn, flowObj);
231 }
232 }
233 } catch (IOException e) {
234 log.error("Failure writing flow mod from network map", e);
235 }
236 }
237 conn.endTx(Transaction.COMMIT);
238 }
239 };
240 final ScheduledFuture<?> readerHandle =
241 scheduler.scheduleAtFixedRate(reader, 3, 3, TimeUnit.SECONDS);
242
243 @Override
244 public void init(String conf) {
245 conn = GraphDBConnection.getInstance(conf);
246 }
247
248 public void finalize() {
249 close();
250 }
251
252 @Override
253 public void close() {
254 conn.close();
255 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800256
257 @Override
258 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
259 Collection<Class<? extends IFloodlightService>> l =
260 new ArrayList<Class<? extends IFloodlightService>>();
261 l.add(IFlowService.class);
262 return l;
263 }
264
265 @Override
266 public Map<Class<? extends IFloodlightService>, IFloodlightService>
267 getServiceImpls() {
268 Map<Class<? extends IFloodlightService>,
269 IFloodlightService> m =
270 new HashMap<Class<? extends IFloodlightService>,
271 IFloodlightService>();
272 m.put(IFlowService.class, this);
273 return m;
274 }
275
276 @Override
277 public Collection<Class<? extends IFloodlightService>>
278 getModuleDependencies() {
279 Collection<Class<? extends IFloodlightService>> l =
280 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800281 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800282 l.add(IRestApiService.class);
283 return l;
284 }
285
286 @Override
287 public void init(FloodlightModuleContext context)
288 throws FloodlightModuleException {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800289 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800290 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800291 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
292 EnumSet.of(OFType.FLOW_MOD),
293 OFMESSAGE_DAMPER_TIMEOUT);
294 // TODO: An ugly hack!
295 String conf = "/tmp/cassandra.titan";
296 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800297 }
298
299 @Override
300 public void startUp(FloodlightModuleContext context) {
301 restApi.addRestletRoutable(new FlowWebRoutable());
302 }
303
304 /**
305 * Add a flow.
306 *
307 * Internally, ONOS will automatically register the installer for
308 * receiving Flow Path Notifications for that path.
309 *
310 * @param flowPath the Flow Path to install.
311 * @param flowId the return-by-reference Flow ID as assigned internally.
312 * @return true on success, otherwise false.
313 */
314 @Override
315 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800316
317 //
318 // Assign the FlowEntry IDs
319 // TODO: This is an ugly hack!
320 // The Flow Entry IDs are set to 1000*FlowId + Index
321 //
322 int i = 1;
323 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
324 long id = flowPath.flowId().value() * 1000 + i;
325 ++i;
326 flowEntry.setFlowEntryId(new FlowEntryId(id));
327 }
328
329 IFlowPath flowObj = null;
330 try {
331 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
332 != null) {
333 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
334 flowPath.flowId().toString());
335 } else {
336 flowObj = conn.utils().newFlowPath(conn);
337 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
338 flowPath.flowId().toString());
339 }
340 } catch (Exception e) {
341 // TODO: handle exceptions
342 conn.endTx(Transaction.ROLLBACK);
343 log.error(":addFlow FlowId:{} failed",
344 flowPath.flowId().toString());
345 }
346 if (flowObj == null)
347 return false;
348
349 //
350 // Set the Flow key:
351 // - flowId
352 //
353 flowObj.setFlowId(flowPath.flowId().toString());
354 flowObj.setType("flow");
355
356 //
357 // Set the Flow attributes:
358 // - flowPath.installerId()
359 // - flowPath.dataPath().srcPort()
360 // - flowPath.dataPath().dstPort()
361 //
362 flowObj.setInstallerId(flowPath.installerId().toString());
363 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
364 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
365 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
366 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
367
368 // Flow edges:
369 // HeadFE
370
371
372 //
373 // Flow Entries:
374 // flowPath.dataPath().flowEntries()
375 //
376 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
377 IFlowEntry flowEntryObj = null;
378 boolean found = false;
379 try {
380 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
381 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
382 flowEntry.flowEntryId().toString());
383 found = true;
384 } else {
385 flowEntryObj = conn.utils().newFlowEntry(conn);
386 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
387 flowEntry.flowEntryId().toString());
388 }
389 } catch (Exception e) {
390 // TODO: handle exceptions
391 conn.endTx(Transaction.ROLLBACK);
392 log.error(":addFlow FlowEntryId:{} failed",
393 flowEntry.flowEntryId().toString());
394 }
395 if (flowEntryObj == null)
396 return false;
397
398 //
399 // Set the Flow Entry key:
400 // - flowEntry.flowEntryId()
401 //
402 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
403 flowEntryObj.setType("flow_entry");
404
405 //
406 // Set the Flow Entry attributes:
407 // - flowEntry.flowEntryMatch()
408 // - flowEntry.flowEntryActions()
409 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800410 // - flowEntry.flowEntryUserState()
411 // - flowEntry.flowEntrySwitchState()
412 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700413 // - flowEntry.matchInPort()
414 // - flowEntry.matchEthernetFrameType()
415 // - flowEntry.matchSrcIPv4Net()
416 // - flowEntry.matchDstIPv4Net()
417 // - flowEntry.matchSrcMac()
418 // - flowEntry.matchDstMac()
419 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800420 //
421 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700422 if (flowEntry.flowEntryMatch().matchInPort())
423 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
424 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
425 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
426 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
427 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
428 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
429 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
430 if (flowEntry.flowEntryMatch().matchSrcMac())
431 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
432 if (flowEntry.flowEntryMatch().matchDstMac())
433 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
434
435 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
436 if (fa.actionOutput() != null)
437 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
438 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 // TODO: Hacks with hard-coded state names!
440 if (found)
441 flowEntryObj.setUserState("FE_USER_MODIFY");
442 else
443 flowEntryObj.setUserState("FE_USER_ADD");
444 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
445 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800446 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447 // and FlowEntryErrorState.
448 //
449
450 // Flow Entries edges:
451 // Flow
452 // NextFE
453 // InPort
454 // OutPort
455 // Switch
456 if (! found)
457 flowObj.addFlowEntry(flowEntryObj);
458 }
459 conn.endTx(Transaction.COMMIT);
460
461 //
462 // TODO: We need a proper Flow ID allocation mechanism.
463 //
464 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800465 return true;
466 }
467
468 /**
469 * Delete a previously added flow.
470 *
471 * @param flowId the Flow ID of the flow to delete.
472 * @return true on success, otherwise false.
473 */
474 @Override
475 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800476 IFlowPath flowObj = null;
477 //
478 // We just mark the entries for deletion,
479 // and let the switches remove each individual entry after
480 // it has been removed from the switches.
481 //
482 try {
483 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
484 != null) {
485 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
486 flowId.toString());
487 } else {
488 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
489 flowId.toString());
490 }
491 } catch (Exception e) {
492 // TODO: handle exceptions
493 conn.endTx(Transaction.ROLLBACK);
494 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
495 }
496 if (flowObj == null)
497 return true; // OK: No such flow
498
499 //
500 // Find and mark for deletion all Flow Entries
501 //
502 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
503 boolean empty = true; // TODO: an ugly hack
504 for (IFlowEntry flowEntryObj : flowEntries) {
505 empty = false;
506 // flowObj.removeFlowEntry(flowEntryObj);
507 // conn.utils().removeFlowEntry(conn, flowEntryObj);
508 flowEntryObj.setUserState("FE_USER_DELETE");
509 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
510 }
511 // Remove from the database empty flows
512 if (empty)
513 conn.utils().removeFlowPath(conn, flowObj);
514 conn.endTx(Transaction.COMMIT);
515
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800516 return true;
517 }
518
519 /**
520 * Get a previously added flow.
521 *
522 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800523 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800524 */
525 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800526 public FlowPath getFlow(FlowId flowId) {
527 IFlowPath flowObj = null;
528 try {
529 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
530 != null) {
531 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
532 flowId.toString());
533 } else {
534 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
535 flowId.toString());
536 }
537 } catch (Exception e) {
538 // TODO: handle exceptions
539 conn.endTx(Transaction.ROLLBACK);
540 log.error(":getFlow FlowId:{} failed", flowId.toString());
541 }
542 if (flowObj == null)
543 return null; // Flow not found
544
545 //
546 // Extract the Flow state
547 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800548 FlowPath flowPath = extractFlowPath(flowObj);
549 conn.endTx(Transaction.COMMIT);
550
551 return flowPath;
552 }
553
554 /**
555 * Get all previously added flows by a specific installer for a given
556 * data path endpoints.
557 *
558 * @param installerId the Caller ID of the installer of the flow to get.
559 * @param dataPathEndpoints the data path endpoints of the flow to get.
560 * @return the Flow Paths if found, otherwise null.
561 */
562 @Override
563 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
564 DataPathEndpoints dataPathEndpoints) {
565 //
566 // TODO: The implementation below is not optimal:
567 // We fetch all flows, and then return only the subset that match
568 // the query conditions.
569 // We should use the appropriate Titan/Gremlin query to filter-out
570 // the flows as appropriate.
571 //
572 ArrayList<FlowPath> allFlows = getAllFlows();
573
574 if (allFlows == null) {
575 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
576 return null;
577 }
578
579 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
580 for (FlowPath flow : allFlows) {
581 //
582 // TODO: String-based comparison is sub-optimal.
583 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800584 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800585 //
586 if (! flow.installerId().toString().equals(installerId.toString()))
587 continue;
588 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
589 continue;
590 }
591 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
592 continue;
593 }
594 flowPaths.add(flow);
595 }
596
597 if (flowPaths.isEmpty()) {
598 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
599 flowPaths = null;
600 } else {
601 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
602 }
603
604 return flowPaths;
605 }
606
607 /**
608 * Get all installed flows by all installers for given data path endpoints.
609 *
610 * @param dataPathEndpoints the data path endpoints of the flows to get.
611 * @return the Flow Paths if found, otherwise null.
612 */
613 @Override
614 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
615 //
616 // TODO: The implementation below is not optimal:
617 // We fetch all flows, and then return only the subset that match
618 // the query conditions.
619 // We should use the appropriate Titan/Gremlin query to filter-out
620 // the flows as appropriate.
621 //
622 ArrayList<FlowPath> allFlows = getAllFlows();
623
624 if (allFlows == null) {
625 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
626 return null;
627 }
628
629 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
630 for (FlowPath flow : allFlows) {
631 //
632 // TODO: String-based comparison is sub-optimal.
633 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800634 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800635 //
636 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
637 continue;
638 }
639 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
640 continue;
641 }
642 flowPaths.add(flow);
643 }
644
645 if (flowPaths.isEmpty()) {
646 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
647 flowPaths = null;
648 } else {
649 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
650 }
651
652 return flowPaths;
653 }
654
655 /**
656 * Get all installed flows by all installers.
657 *
658 * @return the Flow Paths if found, otherwise null.
659 */
660 @Override
661 public ArrayList<FlowPath> getAllFlows() {
662 Iterable<IFlowPath> flowPathsObj = null;
663
664 try {
665 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
666 log.debug("Get all FlowPaths: found FlowPaths");
667 } else {
668 log.debug("Get all FlowPaths: no FlowPaths found");
669 }
670 } catch (Exception e) {
671 // TODO: handle exceptions
672 conn.endTx(Transaction.ROLLBACK);
673 log.error(":getAllFlowPaths failed");
674 }
675 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false))
676 return null; // No Flows found
677
678 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
679 for (IFlowPath flowObj : flowPathsObj) {
680 //
681 // Extract the Flow state
682 //
683 FlowPath flowPath = extractFlowPath(flowObj);
684 flowPaths.add(flowPath);
685 }
686
687 conn.endTx(Transaction.COMMIT);
688
689 return flowPaths;
690 }
691
692 /**
693 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
694 *
695 * @param flowObj the object to extract the Flow Path State from.
696 * @return the extracted Flow Path State.
697 */
698 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800699 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800700
701 //
702 // Extract the Flow state
703 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800704 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
705 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
706 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
707 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
708 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
709 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
710
711 //
712 // Extract all Flow Entries
713 //
714 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
715 for (IFlowEntry flowEntryObj : flowEntries) {
716 FlowEntry flowEntry = new FlowEntry();
717 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
718 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700719
720 //
721 // Extract the match conditions
722 //
723 FlowEntryMatch match = new FlowEntryMatch();
724 Short matchInPort = flowEntryObj.getMatchInPort();
725 if (matchInPort != null)
726 match.enableInPort(new Port(matchInPort));
727 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
728 if (matchEthernetFrameType != null)
729 match.enableEthernetFrameType(matchEthernetFrameType);
730 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
731 if (matchSrcIPv4Net != null)
732 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
733 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
734 if (matchDstIPv4Net != null)
735 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
736 String matchSrcMac = flowEntryObj.getMatchSrcMac();
737 if (matchSrcMac != null)
738 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
739 String matchDstMac = flowEntryObj.getMatchDstMac();
740 if (matchDstMac != null)
741 match.enableDstMac(MACAddress.valueOf(matchDstMac));
742 flowEntry.setFlowEntryMatch(match);
743
744 //
745 // Extract the actions
746 //
747 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
748 Short actionOutputPort = flowEntryObj.getActionOutput();
749 if (actionOutputPort != null) {
750 FlowEntryAction action = new FlowEntryAction();
751 action.setActionOutput(new Port(actionOutputPort));
752 actions.add(action);
753 }
754 flowEntry.setFlowEntryActions(actions);
755
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800756 String userState = flowEntryObj.getUserState();
757 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
758 String switchState = flowEntryObj.getSwitchState();
759 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
760 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800761 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800762 // and FlowEntryErrorState.
763 //
764 flowPath.dataPath().flowEntries().add(flowEntry);
765 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800766
767 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800768 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800769}