blob: 1372c60253cfb0334f57f38800e081ed4357b458 [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;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07006import java.util.Collections;
7import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000010import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000013import java.util.Random;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
15import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080017
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import net.floodlightcontroller.core.IFloodlightProviderService;
19import net.floodlightcontroller.core.INetMapStorage;
20import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
21import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070022import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070023import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070024import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080025import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080030import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
31import net.floodlightcontroller.restserver.IRestApiService;
32import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080034import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070035import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070037import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070039import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080040import net.floodlightcontroller.util.FlowEntrySwitchState;
41import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080042import net.floodlightcontroller.util.FlowId;
43import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.IPv4Net;
45import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.OFMessageDamper;
47import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070048import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.onrc.onos.util.GraphDBConnection;
50import net.onrc.onos.util.GraphDBConnection.Transaction;
51
52import org.openflow.protocol.OFFlowMod;
53import org.openflow.protocol.OFMatch;
54import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070055import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import org.openflow.protocol.OFType;
57import org.openflow.protocol.action.OFAction;
58import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
Jonathan Hartf5315fb2013-04-05 11:41:56 -070062
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070063public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080064
65 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066
67 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070068 protected volatile IFloodlightProviderService floodlightProvider;
69 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070070 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 protected OFMessageDamper messageDamper;
73
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070074 //
75 // TODO: Values copied from elsewhere (class LearningSwitch).
76 // The local copy should go away!
77 //
78 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
79 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
80 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
81 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
82 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080083
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000084 // Flow Entry ID generation state
85 private static Random randomGenerator = new Random();
86 private static int nextFlowEntryIdPrefix = 0;
87 private static int nextFlowEntryIdSuffix = 0;
88 private static long nextFlowEntryId = 0;
89
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070090 private static long measurementFlowId = 100000;
91 private static String measurementFlowIdStr = "0x186a0"; // 100000
92 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070093
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080094 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080095 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
96
97 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070098 private ScheduledExecutorService mapReaderScheduler;
99 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700100
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700101 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700103 try {
104 runImpl();
105 } catch (Exception e) {
106 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
107 conn.endTx(Transaction.ROLLBACK);
108 return;
109 }
110 }
111
112 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700113 long startTime = System.nanoTime();
114 int counterAllFlowEntries = 0;
115 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700116
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800117 if (floodlightProvider == null) {
118 log.debug("FloodlightProvider service not found!");
119 return;
120 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000121 Map<Long, IOFSwitch> mySwitches =
122 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700123 LinkedList<IFlowEntry> addFlowEntries =
124 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000125 LinkedList<IFlowEntry> deleteFlowEntries =
126 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700127
128 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700129 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700130 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700131 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700132 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 Iterable<IFlowEntry> allFlowEntries =
134 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700135 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700136 counterAllFlowEntries++;
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700137 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000138 if ((switchState == null) ||
139 (! switchState.equals("FE_SWITCH_NOT_UPDATED"))) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000140 continue; // Ignore the entry: nothing to do
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000141 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000142
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000143 String dpidStr = flowEntryObj.getSwitchDpid();
144 if (dpidStr == null)
145 continue;
146 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800147 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000148 if (mySwitch == null)
149 continue; // Ignore the entry: not my switch
150
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700151 IFlowPath flowObj =
152 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
153 if (flowObj == null)
154 continue; // Should NOT happen
155 if (flowObj.getFlowId() == null)
156 continue; // Invalid entry
157
158 //
159 // NOTE: For now we process the DELETE before the ADD
160 // to cover the more common scenario.
161 // TODO: This is error prone and needs to be fixed!
162 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000163 String userState = flowEntryObj.getUserState();
164 if (userState == null)
165 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700166 if (userState.equals("FE_USER_DELETE")) {
167 // An entry that needs to be deleted.
168 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700169 installFlowEntry(mySwitch, flowObj, flowEntryObj);
170 } else {
171 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700172 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700173 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700174 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700175 // TODO: Commented-out for now
176 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700177 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700178 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 processed_measurement_flow = true;
180 }
181 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700182 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700183 }
184
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700185 //
186 // Process the Flow Entries that need to be added
187 //
188 for (IFlowEntry flowEntryObj : addFlowEntries) {
189 IFlowPath flowObj =
190 conn.utils().getFlowPathByFlowEntry(conn,
191 flowEntryObj);
192 if (flowObj == null)
193 continue; // Should NOT happen
194 if (flowObj.getFlowId() == null)
195 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700196
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700197 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700198 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000199 if (mySwitch == null)
200 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700201 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800202 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000203
204 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000205 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700206 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000207 //
208 // TODO: We should use the OpenFlow Barrier mechanism
209 // to check for errors, and delete the Flow Entries after the
210 // Barrier message is received.
211 //
212 while (! deleteFlowEntries.isEmpty()) {
213 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
214 IFlowPath flowObj =
215 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
216 if (flowObj == null) {
217 log.debug("Did not find FlowPath to be deleted");
218 continue;
219 }
220 flowObj.removeFlowEntry(flowEntryObj);
221 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000222 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700223
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700224 conn.endTx(Transaction.COMMIT);
225
226 if (processed_measurement_flow) {
227 long estimatedTime =
228 System.nanoTime() - modifiedMeasurementFlowTime;
229 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
230 (double)estimatedTime / 1000000000 + " sec";
231 log.debug(logMsg);
232 }
233
234 long estimatedTime = System.nanoTime() - startTime;
235 double rate = 0.0;
236 if (estimatedTime > 0)
237 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
238 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
239 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
240 counterMyNotUpdatedFlowEntries + " in " +
241 (double)estimatedTime / 1000000000 + " sec: " +
242 rate + " paths/s";
243 log.debug(logMsg);
244 }
245 };
246
247 final Runnable shortestPathReconcile = new Runnable() {
248 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700249 try {
250 runImpl();
251 } catch (Exception e) {
252 log.debug("Exception processing All Flows from the Network MAP: ", e);
253 conn.endTx(Transaction.ROLLBACK);
254 return;
255 }
256 }
257
258 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700259 long startTime = System.nanoTime();
260 int counterAllFlowPaths = 0;
261 int counterMyFlowPaths = 0;
262
263 if (floodlightProvider == null) {
264 log.debug("FloodlightProvider service not found!");
265 return;
266 }
267 Map<Long, IOFSwitch> mySwitches =
268 floodlightProvider.getSwitches();
269 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
270
271 boolean processed_measurement_flow = false;
272
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700273 //
274 // Fetch and recompute the Shortest Path for those
275 // Flow Paths this controller is responsible for.
276 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700277 topoRouteService.prepareShortestPathTopo();
278 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700279 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700280 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700281 if (flowPathObj == null)
282 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700283
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700284 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000285 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700286 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700287 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700288 //
289 // Use the source DPID as a heuristic to decide
290 // which controller is responsible for maintaining the
291 // shortest path.
292 // NOTE: This heuristic is error-prone: if the switch
293 // goes away and no controller is responsible for that
294 // switch, then the original Flow Path is not cleaned-up
295 //
296 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
297 if (mySwitch == null)
298 continue; // Ignore: not my responsibility
299
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700300 // Test the Data Path Summary string
301 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
302 if (dataPathSummaryStr == null)
303 continue; // Could be invalid entry?
304 if (dataPathSummaryStr.isEmpty())
305 continue; // No need to maintain this flow
306
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000307 //
308 // Test whether we need to complete the Flow cleanup,
309 // if the Flow has been deleted by the user.
310 //
311 String flowUserState = flowPathObj.getUserState();
312 if ((flowUserState != null)
313 && flowUserState.equals("FE_USER_DELETE")) {
314 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
315 boolean empty = true; // TODO: an ugly hack
316 for (IFlowEntry flowEntryObj : flowEntries) {
317 empty = false;
318 break;
319 }
320 if (empty)
321 deleteFlows.add(flowPathObj);
322 }
323
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000324 // Fetch the fields needed to recompute the shortest path
325 Short srcPortShort = flowPathObj.getSrcPort();
326 String dstDpidStr = flowPathObj.getDstSwitch();
327 Short dstPortShort = flowPathObj.getDstPort();
328 if ((srcPortShort == null) ||
329 (dstDpidStr == null) ||
330 (dstPortShort == null)) {
331 continue;
332 }
333
334 Port srcPort = new Port(srcPortShort);
335 Dpid dstDpid = new Dpid(dstDpidStr);
336 Port dstPort = new Port(dstPortShort);
337 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
338 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
339
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700340 counterMyFlowPaths++;
341
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700342 //
343 // NOTE: Using here the regular getShortestPath() method
344 // won't work here, because that method calls internally
345 // "conn.endTx(Transaction.COMMIT)", and that will
346 // invalidate all handlers to the Titan database.
347 // If we want to experiment with calling here
348 // getShortestPath(), we need to refactor that code
349 // to avoid closing the transaction.
350 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700351 DataPath dataPath =
352 topoRouteService.getTopoShortestPath(srcSwitchPort,
353 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000354 if (dataPath == null) {
355 // We need the DataPath to compare the paths
356 dataPath = new DataPath();
357 dataPath.setSrcPort(srcSwitchPort);
358 dataPath.setDstPort(dstSwitchPort);
359 }
360
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700361 String newDataPathSummaryStr = dataPath.dataPathSummary();
362 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
363 continue; // Nothing changed
364
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700365 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700366 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000367
368 //
369 // Delete all leftover Flows marked for deletion from the
370 // Network MAP.
371 //
372 while (! deleteFlows.isEmpty()) {
373 IFlowPath flowPathObj = deleteFlows.poll();
374 conn.utils().removeFlowPath(conn, flowPathObj);
375 }
376
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700377 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700378
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800379 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700380
381 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700382 long estimatedTime =
383 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700384 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
385 (double)estimatedTime / 1000000000 + " sec";
386 log.debug(logMsg);
387 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700388
389 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700390 double rate = 0.0;
391 if (estimatedTime > 0)
392 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700393 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700394 counterAllFlowPaths + " MyFlowPaths: " +
395 counterMyFlowPaths + " in " +
396 (double)estimatedTime / 1000000000 + " sec: " +
397 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700398 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800399 }
400 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700401
Jonathan Hart50a94982013-04-10 14:49:51 -0700402 //final ScheduledFuture<?> mapReaderHandle =
403 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800404
Jonathan Hart50a94982013-04-10 14:49:51 -0700405 //final ScheduledFuture<?> shortestPathReconcileHandle =
406 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700407
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800408 @Override
409 public void init(String conf) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700410 conn = GraphDBConnection.getInstance(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800411 }
412
413 public void finalize() {
414 close();
415 }
416
417 @Override
418 public void close() {
419 conn.close();
420 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800421
422 @Override
423 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
424 Collection<Class<? extends IFloodlightService>> l =
425 new ArrayList<Class<? extends IFloodlightService>>();
426 l.add(IFlowService.class);
427 return l;
428 }
429
430 @Override
431 public Map<Class<? extends IFloodlightService>, IFloodlightService>
432 getServiceImpls() {
433 Map<Class<? extends IFloodlightService>,
434 IFloodlightService> m =
435 new HashMap<Class<? extends IFloodlightService>,
436 IFloodlightService>();
437 m.put(IFlowService.class, this);
438 return m;
439 }
440
441 @Override
442 public Collection<Class<? extends IFloodlightService>>
443 getModuleDependencies() {
444 Collection<Class<? extends IFloodlightService>> l =
445 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800446 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700447 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800448 l.add(IRestApiService.class);
449 return l;
450 }
451
452 @Override
453 public void init(FloodlightModuleContext context)
454 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700455 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800456 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700457 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800458 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800459 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
460 EnumSet.of(OFType.FLOW_MOD),
461 OFMESSAGE_DAMPER_TIMEOUT);
462 // TODO: An ugly hack!
463 String conf = "/tmp/cassandra.titan";
464 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700465
466 mapReaderScheduler = Executors.newScheduledThreadPool(1);
467 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800468 }
469
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000470 private long getNextFlowEntryId() {
471 //
472 // Generate the next Flow Entry ID.
473 // NOTE: For now, the higher 32 bits are random, and
474 // the lower 32 bits are sequential.
475 // In the future, we need a better allocation mechanism.
476 //
477 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
478 nextFlowEntryIdPrefix = randomGenerator.nextInt();
479 nextFlowEntryIdSuffix = 0;
480 } else {
481 nextFlowEntryIdSuffix++;
482 }
483 long result = (long)nextFlowEntryIdPrefix << 32;
484 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
485 return result;
486 }
487
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800488 @Override
489 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700490 restApi.addRestletRoutable(new FlowWebRoutable());
491
492 // Initialize the Flow Entry ID generator
493 nextFlowEntryIdPrefix = randomGenerator.nextInt();
494
495 mapReaderScheduler.scheduleAtFixedRate(
496 mapReader, 3, 3, TimeUnit.SECONDS);
497 shortestPathReconcileScheduler.scheduleAtFixedRate(
498 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800499 }
500
501 /**
502 * Add a flow.
503 *
504 * Internally, ONOS will automatically register the installer for
505 * receiving Flow Path Notifications for that path.
506 *
507 * @param flowPath the Flow Path to install.
508 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700509 * @param dataPathSummaryStr the data path summary string if the added
510 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800511 * @return true on success, otherwise false.
512 */
513 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700514 public boolean addFlow(FlowPath flowPath, FlowId flowId,
515 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700516 /*
517 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700518 if (flowPath.flowId().value() == measurementFlowId) {
519 modifiedMeasurementFlowTime = System.nanoTime();
520 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700521 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800522
523 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000524 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800525 try {
526 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
527 != null) {
528 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
529 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000530 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800531 } else {
532 flowObj = conn.utils().newFlowPath(conn);
533 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
534 flowPath.flowId().toString());
535 }
536 } catch (Exception e) {
537 // TODO: handle exceptions
538 conn.endTx(Transaction.ROLLBACK);
539 log.error(":addFlow FlowId:{} failed",
540 flowPath.flowId().toString());
541 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700542 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000543 log.error(":addFlow FlowId:{} failed: Flow object not created",
544 flowPath.flowId().toString());
545 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800546 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700547 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800548
549 //
550 // Set the Flow key:
551 // - flowId
552 //
553 flowObj.setFlowId(flowPath.flowId().toString());
554 flowObj.setType("flow");
555
556 //
557 // Set the Flow attributes:
558 // - flowPath.installerId()
559 // - flowPath.dataPath().srcPort()
560 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700561 // - flowPath.matchEthernetFrameType()
562 // - flowPath.matchSrcIPv4Net()
563 // - flowPath.matchDstIPv4Net()
564 // - flowPath.matchSrcMac()
565 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800566 //
567 flowObj.setInstallerId(flowPath.installerId().toString());
568 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
569 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
570 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
571 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700572 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
573 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
574 }
575 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
576 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
577 }
578 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
579 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
580 }
581 if (flowPath.flowEntryMatch().matchSrcMac()) {
582 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
583 }
584 if (flowPath.flowEntryMatch().matchDstMac()) {
585 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
586 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800587
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700588 if (dataPathSummaryStr != null) {
589 flowObj.setDataPathSummary(dataPathSummaryStr);
590 } else {
591 flowObj.setDataPathSummary("");
592 }
593
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000594 if (found)
595 flowObj.setUserState("FE_USER_MODIFY");
596 else
597 flowObj.setUserState("FE_USER_ADD");
598
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800599 // Flow edges:
600 // HeadFE
601
602
603 //
604 // Flow Entries:
605 // flowPath.dataPath().flowEntries()
606 //
607 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700608 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000609 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800610 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700611 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800612 }
613 conn.endTx(Transaction.COMMIT);
614
615 //
616 // TODO: We need a proper Flow ID allocation mechanism.
617 //
618 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700619
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800620 return true;
621 }
622
623 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700624 * Add a flow entry to the Network MAP.
625 *
626 * @param flowObj the corresponding Flow Path object for the Flow Entry.
627 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700628 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700629 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700630 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700631 // Flow edges
632 // HeadFE (TODO)
633
634 //
635 // Assign the FlowEntry ID.
636 //
637 if ((flowEntry.flowEntryId() == null) ||
638 (flowEntry.flowEntryId().value() == 0)) {
639 long id = getNextFlowEntryId();
640 flowEntry.setFlowEntryId(new FlowEntryId(id));
641 }
642
643 IFlowEntry flowEntryObj = null;
644 boolean found = false;
645 try {
646 if ((flowEntryObj =
647 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
648 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
649 flowEntry.flowEntryId().toString());
650 found = true;
651 } else {
652 flowEntryObj = conn.utils().newFlowEntry(conn);
653 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
654 flowEntry.flowEntryId().toString());
655 }
656 } catch (Exception e) {
657 log.error(":addFlow FlowEntryId:{} failed",
658 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700659 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700660 }
661 if (flowEntryObj == null) {
662 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
663 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700664 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700665 }
666
667 //
668 // Set the Flow Entry key:
669 // - flowEntry.flowEntryId()
670 //
671 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
672 flowEntryObj.setType("flow_entry");
673
674 //
675 // Set the Flow Entry Edges and attributes:
676 // - Switch edge
677 // - InPort edge
678 // - OutPort edge
679 //
680 // - flowEntry.flowEntryMatch()
681 // - flowEntry.flowEntryActions()
682 // - flowEntry.dpid()
683 // - flowEntry.flowEntryUserState()
684 // - flowEntry.flowEntrySwitchState()
685 // - flowEntry.flowEntryErrorState()
686 // - flowEntry.matchInPort()
687 // - flowEntry.matchEthernetFrameType()
688 // - flowEntry.matchSrcIPv4Net()
689 // - flowEntry.matchDstIPv4Net()
690 // - flowEntry.matchSrcMac()
691 // - flowEntry.matchDstMac()
692 // - flowEntry.actionOutput()
693 //
694 ISwitchObject sw =
695 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
696 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
697 flowEntryObj.setSwitch(sw);
698 if (flowEntry.flowEntryMatch().matchInPort()) {
699 IPortObject inport =
700 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
701 flowEntry.flowEntryMatch().inPort().value());
702 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
703 flowEntryObj.setInPort(inport);
704 }
705 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
706 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
707 }
708 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
709 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
710 }
711 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
712 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
713 }
714 if (flowEntry.flowEntryMatch().matchSrcMac()) {
715 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
716 }
717 if (flowEntry.flowEntryMatch().matchDstMac()) {
718 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
719 }
720
721 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
722 if (fa.actionOutput() != null) {
723 IPortObject outport =
724 conn.utils().searchPort(conn,
725 flowEntry.dpid().toString(),
726 fa.actionOutput().port().value());
727 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
728 flowEntryObj.setOutPort(outport);
729 }
730 }
731 // TODO: Hacks with hard-coded state names!
732 if (found)
733 flowEntryObj.setUserState("FE_USER_MODIFY");
734 else
735 flowEntryObj.setUserState("FE_USER_ADD");
736 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
737 //
738 // TODO: Take care of the FlowEntryErrorState.
739 //
740
741 // Flow Entries edges:
742 // Flow
743 // NextFE (TODO)
744 if (! found) {
745 flowObj.addFlowEntry(flowEntryObj);
746 flowEntryObj.setFlow(flowObj);
747 }
748
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700749 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700750 }
751
752 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800753 * Delete a previously added flow.
754 *
755 * @param flowId the Flow ID of the flow to delete.
756 * @return true on success, otherwise false.
757 */
758 @Override
759 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700760 /*
761 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700762 if (flowId.value() == measurementFlowId) {
763 modifiedMeasurementFlowTime = System.nanoTime();
764 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700765 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700766
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800767 IFlowPath flowObj = null;
768 //
769 // We just mark the entries for deletion,
770 // and let the switches remove each individual entry after
771 // it has been removed from the switches.
772 //
773 try {
774 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
775 != null) {
776 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
777 flowId.toString());
778 } else {
779 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
780 flowId.toString());
781 }
782 } catch (Exception e) {
783 // TODO: handle exceptions
784 conn.endTx(Transaction.ROLLBACK);
785 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
786 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700787 if (flowObj == null) {
788 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800789 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700790 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800791
792 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000793 // Find and mark for deletion all Flow Entries,
794 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800795 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000796 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800797 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
798 boolean empty = true; // TODO: an ugly hack
799 for (IFlowEntry flowEntryObj : flowEntries) {
800 empty = false;
801 // flowObj.removeFlowEntry(flowEntryObj);
802 // conn.utils().removeFlowEntry(conn, flowEntryObj);
803 flowEntryObj.setUserState("FE_USER_DELETE");
804 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
805 }
806 // Remove from the database empty flows
807 if (empty)
808 conn.utils().removeFlowPath(conn, flowObj);
809 conn.endTx(Transaction.COMMIT);
810
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800811 return true;
812 }
813
814 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700815 * Clear the state for a previously added flow.
816 *
817 * @param flowId the Flow ID of the flow to clear.
818 * @return true on success, otherwise false.
819 */
820 @Override
821 public boolean clearFlow(FlowId flowId) {
822 IFlowPath flowObj = null;
823 try {
824 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
825 != null) {
826 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
827 flowId.toString());
828 } else {
829 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
830 flowId.toString());
831 }
832 } catch (Exception e) {
833 // TODO: handle exceptions
834 conn.endTx(Transaction.ROLLBACK);
835 log.error(":clearFlow FlowId:{} failed", flowId.toString());
836 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700837 if (flowObj == null) {
838 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700839 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700840 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700841
842 //
843 // Remove all Flow Entries
844 //
845 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
846 for (IFlowEntry flowEntryObj : flowEntries) {
847 flowObj.removeFlowEntry(flowEntryObj);
848 conn.utils().removeFlowEntry(conn, flowEntryObj);
849 }
850 // Remove the Flow itself
851 conn.utils().removeFlowPath(conn, flowObj);
852 conn.endTx(Transaction.COMMIT);
853
854 return true;
855 }
856
857 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800858 * Get a previously added flow.
859 *
860 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800861 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800862 */
863 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800864 public FlowPath getFlow(FlowId flowId) {
865 IFlowPath flowObj = null;
866 try {
867 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
868 != null) {
869 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
870 flowId.toString());
871 } else {
872 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
873 flowId.toString());
874 }
875 } catch (Exception e) {
876 // TODO: handle exceptions
877 conn.endTx(Transaction.ROLLBACK);
878 log.error(":getFlow FlowId:{} failed", flowId.toString());
879 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700880 if (flowObj == null) {
881 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800882 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700883 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800884
885 //
886 // Extract the Flow state
887 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800888 FlowPath flowPath = extractFlowPath(flowObj);
889 conn.endTx(Transaction.COMMIT);
890
891 return flowPath;
892 }
893
894 /**
895 * Get all previously added flows by a specific installer for a given
896 * data path endpoints.
897 *
898 * @param installerId the Caller ID of the installer of the flow to get.
899 * @param dataPathEndpoints the data path endpoints of the flow to get.
900 * @return the Flow Paths if found, otherwise null.
901 */
902 @Override
903 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
904 DataPathEndpoints dataPathEndpoints) {
905 //
906 // TODO: The implementation below is not optimal:
907 // We fetch all flows, and then return only the subset that match
908 // the query conditions.
909 // We should use the appropriate Titan/Gremlin query to filter-out
910 // the flows as appropriate.
911 //
912 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700913 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800914
915 if (allFlows == null) {
916 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700917 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800918 }
919
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800920 for (FlowPath flow : allFlows) {
921 //
922 // TODO: String-based comparison is sub-optimal.
923 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800924 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800925 //
926 if (! flow.installerId().toString().equals(installerId.toString()))
927 continue;
928 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
929 continue;
930 }
931 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
932 continue;
933 }
934 flowPaths.add(flow);
935 }
936
937 if (flowPaths.isEmpty()) {
938 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800939 } else {
940 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
941 }
942
943 return flowPaths;
944 }
945
946 /**
947 * Get all installed flows by all installers for given data path endpoints.
948 *
949 * @param dataPathEndpoints the data path endpoints of the flows to get.
950 * @return the Flow Paths if found, otherwise null.
951 */
952 @Override
953 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
954 //
955 // TODO: The implementation below is not optimal:
956 // We fetch all flows, and then return only the subset that match
957 // the query conditions.
958 // We should use the appropriate Titan/Gremlin query to filter-out
959 // the flows as appropriate.
960 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700961 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
962 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800963
964 if (allFlows == null) {
965 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700966 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800967 }
968
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800969 for (FlowPath flow : allFlows) {
970 //
971 // TODO: String-based comparison is sub-optimal.
972 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800973 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800974 //
975 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
976 continue;
977 }
978 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
979 continue;
980 }
981 flowPaths.add(flow);
982 }
983
984 if (flowPaths.isEmpty()) {
985 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800986 } else {
987 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
988 }
989
990 return flowPaths;
991 }
992
993 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700994 * Get summary of all installed flows by all installers in a given range
995 *
996 * @param flowId the data path endpoints of the flows to get.
997 * @param maxFlows: the maximum number of flows to be returned
998 * @return the Flow Paths if found, otherwise null.
999 */
1000 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001001 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001002
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001003 // TODO: The implementation below is not optimal:
1004 // We fetch all flows, and then return only the subset that match
1005 // the query conditions.
1006 // We should use the appropriate Titan/Gremlin query to filter-out
1007 // the flows as appropriate.
1008 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001009 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001010
Jonathan Hart01f2d272013-04-04 20:03:46 -07001011 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1012
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001013 Collections.sort(flowPathsWithoutFlowEntries,
1014 new Comparator<IFlowPath>(){
1015 @Override
1016 public int compare(IFlowPath first, IFlowPath second) {
1017 // TODO Auto-generated method stub
1018 long result = new FlowId(first.getFlowId()).value()
1019 - new FlowId(second.getFlowId()).value();
1020 if (result > 0) return 1;
1021 else if (result < 0) return -1;
1022 else return 0;
1023 }
1024 }
1025 );
1026
Jonathan Hart01f2d272013-04-04 20:03:46 -07001027 return flowPathsWithoutFlowEntries;
1028
1029 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001030 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001031
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001032 if (allFlows == null) {
1033 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001034 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001035 }
1036
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001037 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001038
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001039 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001040 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001041
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001042 // start from desired flowId
1043 if (flow.flowId().value() < flowId.value()) {
1044 continue;
1045 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001046
1047 // Summarize by making null flow entry fields that are not relevant to report
1048 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1049 flowEntry.setFlowEntryActions(null);
1050 flowEntry.setFlowEntryMatch(null);
1051 }
1052
1053 flowPaths.add(flow);
1054 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1055 break;
1056 }
1057 }
1058
1059 if (flowPaths.isEmpty()) {
1060 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001061 } else {
1062 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1063 }
1064
1065 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001066 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001067 }
1068
1069 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001070 * Get all installed flows by all installers.
1071 *
1072 * @return the Flow Paths if found, otherwise null.
1073 */
1074 @Override
1075 public ArrayList<FlowPath> getAllFlows() {
1076 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001077 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001078
1079 try {
1080 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1081 log.debug("Get all FlowPaths: found FlowPaths");
1082 } else {
1083 log.debug("Get all FlowPaths: no FlowPaths found");
1084 }
1085 } catch (Exception e) {
1086 // TODO: handle exceptions
1087 conn.endTx(Transaction.ROLLBACK);
1088 log.error(":getAllFlowPaths failed");
1089 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001090 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1091 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001092 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001093 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001094
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001095 for (IFlowPath flowObj : flowPathsObj) {
1096 //
1097 // Extract the Flow state
1098 //
1099 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001100 if (flowPath != null)
1101 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001102 }
1103
1104 conn.endTx(Transaction.COMMIT);
1105
1106 return flowPaths;
1107 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001108
1109 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1110 Iterable<IFlowPath> flowPathsObj = null;
1111 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1112 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1113
Jonathan Harte6e91872013-04-13 11:10:32 -07001114 conn.endTx(Transaction.COMMIT);
1115
Jonathan Hart01f2d272013-04-04 20:03:46 -07001116 try {
1117 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1118 log.debug("Get all FlowPaths: found FlowPaths");
1119 } else {
1120 log.debug("Get all FlowPaths: no FlowPaths found");
1121 }
1122 } catch (Exception e) {
1123 // TODO: handle exceptions
1124 conn.endTx(Transaction.ROLLBACK);
1125 log.error(":getAllFlowPaths failed");
1126 }
1127 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1128 return new ArrayList<IFlowPath>(); // No Flows found
1129 }
1130
1131 for (IFlowPath flowObj : flowPathsObj){
1132 flowPathsObjArray.add(flowObj);
1133 }
1134 /*
1135 for (IFlowPath flowObj : flowPathsObj) {
1136 //
1137 // Extract the Flow state
1138 //
1139 FlowPath flowPath = extractFlowPath(flowObj);
1140 if (flowPath != null)
1141 flowPaths.add(flowPath);
1142 }
1143 */
1144
1145 //conn.endTx(Transaction.COMMIT);
1146
1147 return flowPathsObjArray;
1148 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001149
1150 /**
1151 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1152 *
1153 * @param flowObj the object to extract the Flow Path State from.
1154 * @return the extracted Flow Path State.
1155 */
1156 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001157 //
1158 // Extract the Flow state
1159 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001160 String flowIdStr = flowObj.getFlowId();
1161 String installerIdStr = flowObj.getInstallerId();
1162 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001163 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001164 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001165 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001166
1167 if ((flowIdStr == null) ||
1168 (installerIdStr == null) ||
1169 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001170 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001171 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001172 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001173 // TODO: A work-around, becauuse of some bogus database objects
1174 return null;
1175 }
1176
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001177 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001178 flowPath.setFlowId(new FlowId(flowIdStr));
1179 flowPath.setInstallerId(new CallerId(installerIdStr));
1180 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001181 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001182 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001183 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001184 //
1185 // Extract the match conditions common for all Flow Entries
1186 //
1187 {
1188 FlowEntryMatch match = new FlowEntryMatch();
1189 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1190 if (matchEthernetFrameType != null)
1191 match.enableEthernetFrameType(matchEthernetFrameType);
1192 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1193 if (matchSrcIPv4Net != null)
1194 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1195 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1196 if (matchDstIPv4Net != null)
1197 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1198 String matchSrcMac = flowObj.getMatchSrcMac();
1199 if (matchSrcMac != null)
1200 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1201 String matchDstMac = flowObj.getMatchDstMac();
1202 if (matchDstMac != null)
1203 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1204 flowPath.setFlowEntryMatch(match);
1205 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001206
1207 //
1208 // Extract all Flow Entries
1209 //
1210 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1211 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001212 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1213 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001214 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001215 flowPath.dataPath().flowEntries().add(flowEntry);
1216 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001217
1218 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001219 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001220
1221 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001222 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1223 *
1224 * @param flowEntryObj the object to extract the Flow Entry State from.
1225 * @return the extracted Flow Entry State.
1226 */
1227 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1228 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1229 String switchDpidStr = flowEntryObj.getSwitchDpid();
1230 String userState = flowEntryObj.getUserState();
1231 String switchState = flowEntryObj.getSwitchState();
1232
1233 if ((flowEntryIdStr == null) ||
1234 (switchDpidStr == null) ||
1235 (userState == null) ||
1236 (switchState == null)) {
1237 // TODO: A work-around, becauuse of some bogus database objects
1238 return null;
1239 }
1240
1241 FlowEntry flowEntry = new FlowEntry();
1242 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1243 flowEntry.setDpid(new Dpid(switchDpidStr));
1244
1245 //
1246 // Extract the match conditions
1247 //
1248 FlowEntryMatch match = new FlowEntryMatch();
1249 Short matchInPort = flowEntryObj.getMatchInPort();
1250 if (matchInPort != null)
1251 match.enableInPort(new Port(matchInPort));
1252 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1253 if (matchEthernetFrameType != null)
1254 match.enableEthernetFrameType(matchEthernetFrameType);
1255 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1256 if (matchSrcIPv4Net != null)
1257 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1258 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1259 if (matchDstIPv4Net != null)
1260 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1261 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1262 if (matchSrcMac != null)
1263 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1264 String matchDstMac = flowEntryObj.getMatchDstMac();
1265 if (matchDstMac != null)
1266 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1267 flowEntry.setFlowEntryMatch(match);
1268
1269 //
1270 // Extract the actions
1271 //
1272 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1273 Short actionOutputPort = flowEntryObj.getActionOutput();
1274 if (actionOutputPort != null) {
1275 FlowEntryAction action = new FlowEntryAction();
1276 action.setActionOutput(new Port(actionOutputPort));
1277 actions.add(action);
1278 }
1279 flowEntry.setFlowEntryActions(actions);
1280 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1281 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1282 //
1283 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1284 // and FlowEntryErrorState.
1285 //
1286 return flowEntry;
1287 }
1288
1289 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001290 * Add and maintain a shortest-path flow.
1291 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001292 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001293 *
1294 * @param flowPath the Flow Path with the endpoints and the match
1295 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001296 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001297 */
1298 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001299 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001300 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001301 // Don't do the shortest path computation here.
1302 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001303 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001304
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001305 // We need the DataPath to populate the Network MAP
1306 DataPath dataPath = new DataPath();
1307 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1308 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001309
1310 //
1311 // Prepare the computed Flow Path
1312 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001313 FlowPath computedFlowPath = new FlowPath();
1314 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1315 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1316 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001317 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001318
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001319 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001320 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001321 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001322 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001323
1324 // TODO: Mark the flow for maintenance purpose
1325
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001326 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001327 }
1328
1329 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001330 * Reconcile a flow.
1331 *
1332 * @param flowObj the flow that needs to be reconciliated.
1333 * @param newDataPath the new data path to use.
1334 * @return true on success, otherwise false.
1335 */
1336 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1337 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1338
1339 //
1340 // Set the incoming port matching and the outgoing port output
1341 // actions for each flow entry.
1342 //
1343 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1344 // Set the incoming port matching
1345 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1346 flowEntry.setFlowEntryMatch(flowEntryMatch);
1347 flowEntryMatch.enableInPort(flowEntry.inPort());
1348
1349 // Set the outgoing port output action
1350 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1351 if (flowEntryActions == null) {
1352 flowEntryActions = new ArrayList<FlowEntryAction>();
1353 flowEntry.setFlowEntryActions(flowEntryActions);
1354 }
1355 FlowEntryAction flowEntryAction = new FlowEntryAction();
1356 flowEntryAction.setActionOutput(flowEntry.outPort());
1357 flowEntryActions.add(flowEntryAction);
1358 }
1359
1360 //
1361 // Remove the old Flow Entries, and add the new Flow Entries
1362 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001363 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1364 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1365 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001366 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001367 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001368 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001369 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001370 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001371 }
1372
1373 //
1374 // Set the Data Path Summary
1375 //
1376 String dataPathSummaryStr = newDataPath.dataPathSummary();
1377 flowObj.setDataPathSummary(dataPathSummaryStr);
1378
1379 return true;
1380 }
1381
1382 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001383 * Reconcile all flows in a set.
1384 *
1385 * @param flowObjSet the set of flows that need to be reconciliated.
1386 */
1387 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1388 if (! flowObjSet.iterator().hasNext())
1389 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001390 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001391 }
1392
1393 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001394 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001395 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001396 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001397 * @param flowObj the flow path object for the flow entry to install.
1398 * @param flowEntryObj the flow entry object to install.
1399 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001400 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001401 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1402 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001403 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1404 if (flowEntryIdStr == null)
1405 return false;
1406 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001407 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001408 if (userState == null)
1409 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001410
1411 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001412 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001413 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001414 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1415 .getMessage(OFType.FLOW_MOD);
1416 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001417
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001418 short flowModCommand = OFFlowMod.OFPFC_ADD;
1419 if (userState.equals("FE_USER_ADD")) {
1420 flowModCommand = OFFlowMod.OFPFC_ADD;
1421 } else if (userState.equals("FE_USER_MODIFY")) {
1422 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1423 } else if (userState.equals("FE_USER_DELETE")) {
1424 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1425 } else {
1426 // Unknown user state. Ignore the entry
1427 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1428 flowEntryId.toString(), userState);
1429 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001430 }
1431
1432 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001433 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001434 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001435 // NOTE: The Flow matching conditions common for all Flow Entries are
1436 // used ONLY if a Flow Entry does NOT have the corresponding matching
1437 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001438 //
1439 OFMatch match = new OFMatch();
1440 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001441
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001442 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001443 Short matchInPort = flowEntryObj.getMatchInPort();
1444 if (matchInPort != null) {
1445 match.setInputPort(matchInPort);
1446 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1447 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001448
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001449 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001450 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1451 if (matchEthernetFrameType == null)
1452 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1453 if (matchEthernetFrameType != null) {
1454 match.setDataLayerType(matchEthernetFrameType);
1455 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1456 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001457
1458 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001459 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1460 if (matchSrcIPv4Net == null)
1461 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1462 if (matchSrcIPv4Net != null) {
1463 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1464 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001465
1466 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001467 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1468 if (matchDstIPv4Net == null)
1469 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1470 if (matchDstIPv4Net != null) {
1471 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1472 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001473
1474 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001475 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1476 if (matchSrcMac == null)
1477 matchSrcMac = flowObj.getMatchSrcMac();
1478 if (matchSrcMac != null) {
1479 match.setDataLayerSource(matchSrcMac);
1480 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1481 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001482
1483 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001484 String matchDstMac = flowEntryObj.getMatchDstMac();
1485 if (matchDstMac == null)
1486 matchDstMac = flowObj.getMatchDstMac();
1487 if (matchDstMac != null) {
1488 match.setDataLayerDestination(matchDstMac);
1489 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1490 }
1491
1492 //
1493 // Fetch the actions
1494 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001495 // TODO: For now we support only the "OUTPUT" actions.
1496 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001497 List<OFAction> actions = new ArrayList<OFAction>();
1498 Short actionOutputPort = flowEntryObj.getActionOutput();
1499 if (actionOutputPort != null) {
1500 OFActionOutput action = new OFActionOutput();
1501 // XXX: The max length is hard-coded for now
1502 action.setMaxLength((short)0xffff);
1503 action.setPort(actionOutputPort);
1504 actions.add(action);
1505 }
1506
1507 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1508 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1509 .setPriority(PRIORITY_DEFAULT)
1510 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1511 .setCookie(cookie)
1512 .setCommand(flowModCommand)
1513 .setMatch(match)
1514 .setActions(actions)
1515 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1516 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1517 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1518 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1519 if (actionOutputPort != null)
1520 fm.setOutPort(actionOutputPort);
1521 }
1522
1523 //
1524 // TODO: Set the following flag
1525 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1526 // See method ForwardingBase::pushRoute()
1527 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001528
1529 //
1530 // Write the message to the switch
1531 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001532 log.debug("MEASUREMENT: Installing flow entry " + userState +
1533 " into switch DPID: " +
1534 mySwitch.getStringId() +
1535 " flowEntryId: " + flowEntryId.toString() +
1536 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1537 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1538 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001539 try {
1540 messageDamper.write(mySwitch, fm, null);
1541 mySwitch.flush();
1542 //
1543 // TODO: We should use the OpenFlow Barrier mechanism
1544 // to check for errors, and update the SwitchState
1545 // for a flow entry after the Barrier message is
1546 // is received.
1547 //
1548 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1549 } catch (IOException e) {
1550 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001551 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001552 }
1553
1554 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001555 }
1556
1557 /**
1558 * Install a Flow Entry on a switch.
1559 *
1560 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001561 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001562 * @param flowEntry the flow entry to install.
1563 * @return true on success, otherwise false.
1564 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001565 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1566 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001567 //
1568 // Create the OpenFlow Flow Modification Entry to push
1569 //
1570 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1571 .getMessage(OFType.FLOW_MOD);
1572 long cookie = flowEntry.flowEntryId().value();
1573
1574 short flowModCommand = OFFlowMod.OFPFC_ADD;
1575 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1576 flowModCommand = OFFlowMod.OFPFC_ADD;
1577 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1578 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1579 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1580 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1581 } else {
1582 // Unknown user state. Ignore the entry
1583 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1584 flowEntry.flowEntryId().toString(),
1585 flowEntry.flowEntryUserState());
1586 return false;
1587 }
1588
1589 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001590 // Fetch the match conditions.
1591 //
1592 // NOTE: The Flow matching conditions common for all Flow Entries are
1593 // used ONLY if a Flow Entry does NOT have the corresponding matching
1594 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001595 //
1596 OFMatch match = new OFMatch();
1597 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001598 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1599 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1600
1601 // Match the Incoming Port
1602 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001603 if (matchInPort != null) {
1604 match.setInputPort(matchInPort.value());
1605 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1606 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001607
1608 // Match the Ethernet Frame Type
1609 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1610 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1611 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1612 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001613 if (matchEthernetFrameType != null) {
1614 match.setDataLayerType(matchEthernetFrameType);
1615 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1616 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001617
1618 // Match the Source IPv4 Network prefix
1619 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1620 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1621 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1622 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001623 if (matchSrcIPv4Net != null) {
1624 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1625 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001626
1627 // Natch the Destination IPv4 Network prefix
1628 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1629 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1630 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1631 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001632 if (matchDstIPv4Net != null) {
1633 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1634 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001635
1636 // Match the Source MAC address
1637 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1638 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1639 matchSrcMac = flowPathMatch.srcMac();
1640 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001641 if (matchSrcMac != null) {
1642 match.setDataLayerSource(matchSrcMac.toString());
1643 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1644 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001645
1646 // Match the Destination MAC address
1647 MACAddress matchDstMac = flowEntryMatch.dstMac();
1648 if ((matchDstMac == null) && (flowPathMatch != null)) {
1649 matchDstMac = flowPathMatch.dstMac();
1650 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001651 if (matchDstMac != null) {
1652 match.setDataLayerDestination(matchDstMac.toString());
1653 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1654 }
1655
1656 //
1657 // Fetch the actions
1658 //
1659 // TODO: For now we support only the "OUTPUT" actions.
1660 //
1661 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1662 List<OFAction> actions = new ArrayList<OFAction>();
1663 ArrayList<FlowEntryAction> flowEntryActions =
1664 flowEntry.flowEntryActions();
1665 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1666 FlowEntryAction.ActionOutput actionOutput =
1667 flowEntryAction.actionOutput();
1668 if (actionOutput != null) {
1669 short actionOutputPort = actionOutput.port().value();
1670 OFActionOutput action = new OFActionOutput();
1671 // XXX: The max length is hard-coded for now
1672 action.setMaxLength((short)0xffff);
1673 action.setPort(actionOutputPort);
1674 actions.add(action);
1675 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1676 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1677 fm.setOutPort(actionOutputPort);
1678 }
1679 }
1680 }
1681
1682 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1683 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1684 .setPriority(PRIORITY_DEFAULT)
1685 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1686 .setCookie(cookie)
1687 .setCommand(flowModCommand)
1688 .setMatch(match)
1689 .setActions(actions)
1690 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1691
1692 //
1693 // TODO: Set the following flag
1694 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1695 // See method ForwardingBase::pushRoute()
1696 //
1697
1698 //
1699 // Write the message to the switch
1700 //
1701 try {
1702 messageDamper.write(mySwitch, fm, null);
1703 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001704 //
1705 // TODO: We should use the OpenFlow Barrier mechanism
1706 // to check for errors, and update the SwitchState
1707 // for a flow entry after the Barrier message is
1708 // is received.
1709 //
1710 // TODO: The FlowEntry Object in Titan should be set
1711 // to FE_SWITCH_UPDATED.
1712 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001713 } catch (IOException e) {
1714 log.error("Failure writing flow mod from network map", e);
1715 return false;
1716 }
1717 return true;
1718 }
1719
1720 /**
1721 * Remove a Flow Entry from a switch.
1722 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001723 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001724 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001725 * @param flowEntry the flow entry to remove.
1726 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001727 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001728 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1729 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001730 //
1731 // The installFlowEntry() method implements both installation
1732 // and removal of flow entries.
1733 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001734 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001735 }
1736
1737 /**
1738 * Install a Flow Entry on a remote controller.
1739 *
1740 * TODO: We need it now: Jono
1741 * - For now it will make a REST call to the remote controller.
1742 * - Internally, it needs to know the name of the remote controller.
1743 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001744 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001745 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001746 * @return true on success, otherwise false.
1747 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001748 public boolean installRemoteFlowEntry(FlowPath flowPath,
1749 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001750 // TODO: We need it now: Jono
1751 // - For now it will make a REST call to the remote controller.
1752 // - Internally, it needs to know the name of the remote controller.
1753 return true;
1754 }
1755
1756 /**
1757 * Remove a flow entry on a remote controller.
1758 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001759 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001760 * @param flowEntry the flow entry to remove.
1761 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001762 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001763 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1764 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001765 //
1766 // The installRemoteFlowEntry() method implements both installation
1767 // and removal of flow entries.
1768 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001769 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001770 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001771}