blob: ace006d4003a2f0fe751853e375ab4e838df914b [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;
Pavlin Radoslavove0575292013-03-28 05:35:25 -070010import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000011import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000014import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070015import java.util.TreeMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.Executors;
17import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.ScheduledFuture;
19import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
22import net.floodlightcontroller.core.INetMapStorage;
23import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070025import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070026import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070027import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080028import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080029import net.floodlightcontroller.core.module.FloodlightModuleContext;
30import net.floodlightcontroller.core.module.FloodlightModuleException;
31import net.floodlightcontroller.core.module.IFloodlightModule;
32import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080033import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
34import net.floodlightcontroller.restserver.IRestApiService;
35import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080037import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070038import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070040import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070042import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.FlowEntrySwitchState;
44import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080045import net.floodlightcontroller.util.FlowId;
46import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070047import net.floodlightcontroller.util.IPv4Net;
48import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.floodlightcontroller.util.OFMessageDamper;
50import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070051import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052import net.onrc.onos.util.GraphDBConnection;
53import net.onrc.onos.util.GraphDBConnection.Transaction;
54
55import org.openflow.protocol.OFFlowMod;
56import org.openflow.protocol.OFMatch;
57import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070058import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059import org.openflow.protocol.OFType;
60import org.openflow.protocol.action.OFAction;
61import org.openflow.protocol.action.OFActionOutput;
Jonathan Hartf5315fb2013-04-05 11:41:56 -070062import org.openflow.util.HexString;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
Jonathan Hartf5315fb2013-04-05 11:41:56 -070066
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070067public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068
69 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070
71 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070073 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070074 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075
76 protected OFMessageDamper messageDamper;
77
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070078 //
79 // TODO: Values copied from elsewhere (class LearningSwitch).
80 // The local copy should go away!
81 //
82 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
83 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
84 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
85 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
86 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080087
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000088 // Flow Entry ID generation state
89 private static Random randomGenerator = new Random();
90 private static int nextFlowEntryIdPrefix = 0;
91 private static int nextFlowEntryIdSuffix = 0;
92 private static long nextFlowEntryId = 0;
93
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070094 private static long measurementFlowId = 100000;
95 private static String measurementFlowIdStr = "0x186a0"; // 100000
96 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070097
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080098 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080099 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
100
101 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700102 private final ScheduledExecutorService mapReaderScheduler =
103 Executors.newScheduledThreadPool(1);
104
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700105 private final ScheduledExecutorService shortestPathReconcileScheduler =
106 Executors.newScheduledThreadPool(1);
107
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700108 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800109 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700110 long startTime = System.nanoTime();
111 int counterAllFlowEntries = 0;
112 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700113
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800114 if (floodlightProvider == null) {
115 log.debug("FloodlightProvider service not found!");
116 return;
117 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000118 Map<Long, IOFSwitch> mySwitches =
119 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700120 LinkedList<IFlowEntry> addFlowEntries =
121 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000122 LinkedList<IFlowEntry> deleteFlowEntries =
123 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700124
125 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700126 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700127 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700128 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700129 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 Iterable<IFlowEntry> allFlowEntries =
131 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700132 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700133 counterAllFlowEntries++;
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700134 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000135 if ((switchState == null) ||
136 (! switchState.equals("FE_SWITCH_NOT_UPDATED"))) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000137 continue; // Ignore the entry: nothing to do
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000138 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000140 String dpidStr = flowEntryObj.getSwitchDpid();
141 if (dpidStr == null)
142 continue;
143 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800144 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000145 if (mySwitch == null)
146 continue; // Ignore the entry: not my switch
147
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700148 IFlowPath flowObj =
149 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
150 if (flowObj == null)
151 continue; // Should NOT happen
152 if (flowObj.getFlowId() == null)
153 continue; // Invalid entry
154
155 //
156 // NOTE: For now we process the DELETE before the ADD
157 // to cover the more common scenario.
158 // TODO: This is error prone and needs to be fixed!
159 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000160 String userState = flowEntryObj.getUserState();
161 if (userState == null)
162 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700163 if (userState.equals("FE_USER_DELETE")) {
164 // An entry that needs to be deleted.
165 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 installFlowEntry(mySwitch, flowObj, flowEntryObj);
167 } else {
168 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700169 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700170 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700171 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700172 // TODO: Commented-out for now
173 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700174 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700175 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700176 processed_measurement_flow = true;
177 }
178 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700179 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700180 }
181
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700182 //
183 // Process the Flow Entries that need to be added
184 //
185 for (IFlowEntry flowEntryObj : addFlowEntries) {
186 IFlowPath flowObj =
187 conn.utils().getFlowPathByFlowEntry(conn,
188 flowEntryObj);
189 if (flowObj == null)
190 continue; // Should NOT happen
191 if (flowObj.getFlowId() == null)
192 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700193
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700194 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700195 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000196 if (mySwitch == null)
197 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700198 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800199 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200
201 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000202 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700203 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204 //
205 // TODO: We should use the OpenFlow Barrier mechanism
206 // to check for errors, and delete the Flow Entries after the
207 // Barrier message is received.
208 //
209 while (! deleteFlowEntries.isEmpty()) {
210 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
211 IFlowPath flowObj =
212 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
213 if (flowObj == null) {
214 log.debug("Did not find FlowPath to be deleted");
215 continue;
216 }
217 flowObj.removeFlowEntry(flowEntryObj);
218 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000219 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700220
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700221 conn.endTx(Transaction.COMMIT);
222
223 if (processed_measurement_flow) {
224 long estimatedTime =
225 System.nanoTime() - modifiedMeasurementFlowTime;
226 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
227 (double)estimatedTime / 1000000000 + " sec";
228 log.debug(logMsg);
229 }
230
231 long estimatedTime = System.nanoTime() - startTime;
232 double rate = 0.0;
233 if (estimatedTime > 0)
234 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
235 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
236 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
237 counterMyNotUpdatedFlowEntries + " in " +
238 (double)estimatedTime / 1000000000 + " sec: " +
239 rate + " paths/s";
240 log.debug(logMsg);
241 }
242 };
243
244 final Runnable shortestPathReconcile = new Runnable() {
245 public void run() {
246 long startTime = System.nanoTime();
247 int counterAllFlowPaths = 0;
248 int counterMyFlowPaths = 0;
249
250 if (floodlightProvider == null) {
251 log.debug("FloodlightProvider service not found!");
252 return;
253 }
254 Map<Long, IOFSwitch> mySwitches =
255 floodlightProvider.getSwitches();
256 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
257
258 boolean processed_measurement_flow = false;
259
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700260 //
261 // Fetch and recompute the Shortest Path for those
262 // Flow Paths this controller is responsible for.
263 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700264 topoRouteService.prepareShortestPathTopo();
265 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700266 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700267 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700268 if (flowPathObj == null)
269 continue;
270 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
271 if (dataPathSummaryStr == null)
272 continue; // Could be invalid entry?
273 if (dataPathSummaryStr.isEmpty())
274 continue; // No need to maintain this flow
275
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700276 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000277 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700278 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700279 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700280 //
281 // Use the source DPID as a heuristic to decide
282 // which controller is responsible for maintaining the
283 // shortest path.
284 // NOTE: This heuristic is error-prone: if the switch
285 // goes away and no controller is responsible for that
286 // switch, then the original Flow Path is not cleaned-up
287 //
288 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
289 if (mySwitch == null)
290 continue; // Ignore: not my responsibility
291
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000292 //
293 // Test whether we need to complete the Flow cleanup,
294 // if the Flow has been deleted by the user.
295 //
296 String flowUserState = flowPathObj.getUserState();
297 if ((flowUserState != null)
298 && flowUserState.equals("FE_USER_DELETE")) {
299 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
300 boolean empty = true; // TODO: an ugly hack
301 for (IFlowEntry flowEntryObj : flowEntries) {
302 empty = false;
303 break;
304 }
305 if (empty)
306 deleteFlows.add(flowPathObj);
307 }
308
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000309 // Fetch the fields needed to recompute the shortest path
310 Short srcPortShort = flowPathObj.getSrcPort();
311 String dstDpidStr = flowPathObj.getDstSwitch();
312 Short dstPortShort = flowPathObj.getDstPort();
313 if ((srcPortShort == null) ||
314 (dstDpidStr == null) ||
315 (dstPortShort == null)) {
316 continue;
317 }
318
319 Port srcPort = new Port(srcPortShort);
320 Dpid dstDpid = new Dpid(dstDpidStr);
321 Port dstPort = new Port(dstPortShort);
322 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
323 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
324
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700325 counterMyFlowPaths++;
326
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700327 //
328 // NOTE: Using here the regular getShortestPath() method
329 // won't work here, because that method calls internally
330 // "conn.endTx(Transaction.COMMIT)", and that will
331 // invalidate all handlers to the Titan database.
332 // If we want to experiment with calling here
333 // getShortestPath(), we need to refactor that code
334 // to avoid closing the transaction.
335 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700336 DataPath dataPath =
337 topoRouteService.getTopoShortestPath(srcSwitchPort,
338 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000339 if (dataPath == null) {
340 // We need the DataPath to compare the paths
341 dataPath = new DataPath();
342 dataPath.setSrcPort(srcSwitchPort);
343 dataPath.setDstPort(dstSwitchPort);
344 }
345
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700346 String newDataPathSummaryStr = dataPath.dataPathSummary();
347 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
348 continue; // Nothing changed
349
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700350 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700351 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000352
353 //
354 // Delete all leftover Flows marked for deletion from the
355 // Network MAP.
356 //
357 while (! deleteFlows.isEmpty()) {
358 IFlowPath flowPathObj = deleteFlows.poll();
359 conn.utils().removeFlowPath(conn, flowPathObj);
360 }
361
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700362 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700363
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800364 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700365
366 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700367 long estimatedTime =
368 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700369 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
370 (double)estimatedTime / 1000000000 + " sec";
371 log.debug(logMsg);
372 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700373
374 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700375 double rate = 0.0;
376 if (estimatedTime > 0)
377 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700378 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700379 counterAllFlowPaths + " MyFlowPaths: " +
380 counterMyFlowPaths + " in " +
381 (double)estimatedTime / 1000000000 + " sec: " +
382 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700383 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800384 }
385 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700386
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700387 final ScheduledFuture<?> mapReaderHandle =
388 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800389
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700390 final ScheduledFuture<?> shortestPathReconcileHandle =
391 shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
392
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800393 @Override
394 public void init(String conf) {
395 conn = GraphDBConnection.getInstance(conf);
396 }
397
398 public void finalize() {
399 close();
400 }
401
402 @Override
403 public void close() {
404 conn.close();
405 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800406
407 @Override
408 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
409 Collection<Class<? extends IFloodlightService>> l =
410 new ArrayList<Class<? extends IFloodlightService>>();
411 l.add(IFlowService.class);
412 return l;
413 }
414
415 @Override
416 public Map<Class<? extends IFloodlightService>, IFloodlightService>
417 getServiceImpls() {
418 Map<Class<? extends IFloodlightService>,
419 IFloodlightService> m =
420 new HashMap<Class<? extends IFloodlightService>,
421 IFloodlightService>();
422 m.put(IFlowService.class, this);
423 return m;
424 }
425
426 @Override
427 public Collection<Class<? extends IFloodlightService>>
428 getModuleDependencies() {
429 Collection<Class<? extends IFloodlightService>> l =
430 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800431 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700432 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800433 l.add(IRestApiService.class);
434 return l;
435 }
436
437 @Override
438 public void init(FloodlightModuleContext context)
439 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700440 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800441 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700442 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800443 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800444 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
445 EnumSet.of(OFType.FLOW_MOD),
446 OFMESSAGE_DAMPER_TIMEOUT);
447 // TODO: An ugly hack!
448 String conf = "/tmp/cassandra.titan";
449 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800450 }
451
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000452 private long getNextFlowEntryId() {
453 //
454 // Generate the next Flow Entry ID.
455 // NOTE: For now, the higher 32 bits are random, and
456 // the lower 32 bits are sequential.
457 // In the future, we need a better allocation mechanism.
458 //
459 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
460 nextFlowEntryIdPrefix = randomGenerator.nextInt();
461 nextFlowEntryIdSuffix = 0;
462 } else {
463 nextFlowEntryIdSuffix++;
464 }
465 long result = (long)nextFlowEntryIdPrefix << 32;
466 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
467 return result;
468 }
469
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800470 @Override
471 public void startUp(FloodlightModuleContext context) {
472 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700473
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000474 // Initialize the Flow Entry ID generator
475 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800476 }
477
478 /**
479 * Add a flow.
480 *
481 * Internally, ONOS will automatically register the installer for
482 * receiving Flow Path Notifications for that path.
483 *
484 * @param flowPath the Flow Path to install.
485 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700486 * @param dataPathSummaryStr the data path summary string if the added
487 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800488 * @return true on success, otherwise false.
489 */
490 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700491 public boolean addFlow(FlowPath flowPath, FlowId flowId,
492 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700493 /*
494 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700495 if (flowPath.flowId().value() == measurementFlowId) {
496 modifiedMeasurementFlowTime = System.nanoTime();
497 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700498 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800499
500 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000501 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800502 try {
503 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
504 != null) {
505 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
506 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000507 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800508 } else {
509 flowObj = conn.utils().newFlowPath(conn);
510 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
511 flowPath.flowId().toString());
512 }
513 } catch (Exception e) {
514 // TODO: handle exceptions
515 conn.endTx(Transaction.ROLLBACK);
516 log.error(":addFlow FlowId:{} failed",
517 flowPath.flowId().toString());
518 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700519 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000520 log.error(":addFlow FlowId:{} failed: Flow object not created",
521 flowPath.flowId().toString());
522 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800523 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700524 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800525
526 //
527 // Set the Flow key:
528 // - flowId
529 //
530 flowObj.setFlowId(flowPath.flowId().toString());
531 flowObj.setType("flow");
532
533 //
534 // Set the Flow attributes:
535 // - flowPath.installerId()
536 // - flowPath.dataPath().srcPort()
537 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700538 // - flowPath.matchEthernetFrameType()
539 // - flowPath.matchSrcIPv4Net()
540 // - flowPath.matchDstIPv4Net()
541 // - flowPath.matchSrcMac()
542 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800543 //
544 flowObj.setInstallerId(flowPath.installerId().toString());
545 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
546 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
547 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
548 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700549 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
550 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
551 }
552 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
553 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
554 }
555 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
556 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
557 }
558 if (flowPath.flowEntryMatch().matchSrcMac()) {
559 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
560 }
561 if (flowPath.flowEntryMatch().matchDstMac()) {
562 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
563 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800564
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700565 if (dataPathSummaryStr != null) {
566 flowObj.setDataPathSummary(dataPathSummaryStr);
567 } else {
568 flowObj.setDataPathSummary("");
569 }
570
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000571 if (found)
572 flowObj.setUserState("FE_USER_MODIFY");
573 else
574 flowObj.setUserState("FE_USER_ADD");
575
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800576 // Flow edges:
577 // HeadFE
578
579
580 //
581 // Flow Entries:
582 // flowPath.dataPath().flowEntries()
583 //
584 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700585 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000586 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800587 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700588 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800589 }
590 conn.endTx(Transaction.COMMIT);
591
592 //
593 // TODO: We need a proper Flow ID allocation mechanism.
594 //
595 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700596
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800597 return true;
598 }
599
600 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700601 * Add a flow entry to the Network MAP.
602 *
603 * @param flowObj the corresponding Flow Path object for the Flow Entry.
604 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700605 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700606 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700607 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700608 // Flow edges
609 // HeadFE (TODO)
610
611 //
612 // Assign the FlowEntry ID.
613 //
614 if ((flowEntry.flowEntryId() == null) ||
615 (flowEntry.flowEntryId().value() == 0)) {
616 long id = getNextFlowEntryId();
617 flowEntry.setFlowEntryId(new FlowEntryId(id));
618 }
619
620 IFlowEntry flowEntryObj = null;
621 boolean found = false;
622 try {
623 if ((flowEntryObj =
624 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
625 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
626 flowEntry.flowEntryId().toString());
627 found = true;
628 } else {
629 flowEntryObj = conn.utils().newFlowEntry(conn);
630 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
631 flowEntry.flowEntryId().toString());
632 }
633 } catch (Exception e) {
634 log.error(":addFlow FlowEntryId:{} failed",
635 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700636 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700637 }
638 if (flowEntryObj == null) {
639 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
640 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700641 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700642 }
643
644 //
645 // Set the Flow Entry key:
646 // - flowEntry.flowEntryId()
647 //
648 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
649 flowEntryObj.setType("flow_entry");
650
651 //
652 // Set the Flow Entry Edges and attributes:
653 // - Switch edge
654 // - InPort edge
655 // - OutPort edge
656 //
657 // - flowEntry.flowEntryMatch()
658 // - flowEntry.flowEntryActions()
659 // - flowEntry.dpid()
660 // - flowEntry.flowEntryUserState()
661 // - flowEntry.flowEntrySwitchState()
662 // - flowEntry.flowEntryErrorState()
663 // - flowEntry.matchInPort()
664 // - flowEntry.matchEthernetFrameType()
665 // - flowEntry.matchSrcIPv4Net()
666 // - flowEntry.matchDstIPv4Net()
667 // - flowEntry.matchSrcMac()
668 // - flowEntry.matchDstMac()
669 // - flowEntry.actionOutput()
670 //
671 ISwitchObject sw =
672 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
673 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
674 flowEntryObj.setSwitch(sw);
675 if (flowEntry.flowEntryMatch().matchInPort()) {
676 IPortObject inport =
677 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
678 flowEntry.flowEntryMatch().inPort().value());
679 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
680 flowEntryObj.setInPort(inport);
681 }
682 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
683 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
684 }
685 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
686 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
687 }
688 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
689 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
690 }
691 if (flowEntry.flowEntryMatch().matchSrcMac()) {
692 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
693 }
694 if (flowEntry.flowEntryMatch().matchDstMac()) {
695 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
696 }
697
698 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
699 if (fa.actionOutput() != null) {
700 IPortObject outport =
701 conn.utils().searchPort(conn,
702 flowEntry.dpid().toString(),
703 fa.actionOutput().port().value());
704 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
705 flowEntryObj.setOutPort(outport);
706 }
707 }
708 // TODO: Hacks with hard-coded state names!
709 if (found)
710 flowEntryObj.setUserState("FE_USER_MODIFY");
711 else
712 flowEntryObj.setUserState("FE_USER_ADD");
713 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
714 //
715 // TODO: Take care of the FlowEntryErrorState.
716 //
717
718 // Flow Entries edges:
719 // Flow
720 // NextFE (TODO)
721 if (! found) {
722 flowObj.addFlowEntry(flowEntryObj);
723 flowEntryObj.setFlow(flowObj);
724 }
725
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700726 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700727 }
728
729 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800730 * Delete a previously added flow.
731 *
732 * @param flowId the Flow ID of the flow to delete.
733 * @return true on success, otherwise false.
734 */
735 @Override
736 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700737 /*
738 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700739 if (flowId.value() == measurementFlowId) {
740 modifiedMeasurementFlowTime = System.nanoTime();
741 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700742 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700743
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800744 IFlowPath flowObj = null;
745 //
746 // We just mark the entries for deletion,
747 // and let the switches remove each individual entry after
748 // it has been removed from the switches.
749 //
750 try {
751 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
752 != null) {
753 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
754 flowId.toString());
755 } else {
756 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
757 flowId.toString());
758 }
759 } catch (Exception e) {
760 // TODO: handle exceptions
761 conn.endTx(Transaction.ROLLBACK);
762 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
763 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700764 if (flowObj == null) {
765 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800766 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700767 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800768
769 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000770 // Find and mark for deletion all Flow Entries,
771 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800772 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000773 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800774 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
775 boolean empty = true; // TODO: an ugly hack
776 for (IFlowEntry flowEntryObj : flowEntries) {
777 empty = false;
778 // flowObj.removeFlowEntry(flowEntryObj);
779 // conn.utils().removeFlowEntry(conn, flowEntryObj);
780 flowEntryObj.setUserState("FE_USER_DELETE");
781 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
782 }
783 // Remove from the database empty flows
784 if (empty)
785 conn.utils().removeFlowPath(conn, flowObj);
786 conn.endTx(Transaction.COMMIT);
787
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800788 return true;
789 }
790
791 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700792 * Clear the state for a previously added flow.
793 *
794 * @param flowId the Flow ID of the flow to clear.
795 * @return true on success, otherwise false.
796 */
797 @Override
798 public boolean clearFlow(FlowId flowId) {
799 IFlowPath flowObj = null;
800 try {
801 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
802 != null) {
803 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
804 flowId.toString());
805 } else {
806 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
807 flowId.toString());
808 }
809 } catch (Exception e) {
810 // TODO: handle exceptions
811 conn.endTx(Transaction.ROLLBACK);
812 log.error(":clearFlow FlowId:{} failed", flowId.toString());
813 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700814 if (flowObj == null) {
815 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700816 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700817 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700818
819 //
820 // Remove all Flow Entries
821 //
822 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
823 for (IFlowEntry flowEntryObj : flowEntries) {
824 flowObj.removeFlowEntry(flowEntryObj);
825 conn.utils().removeFlowEntry(conn, flowEntryObj);
826 }
827 // Remove the Flow itself
828 conn.utils().removeFlowPath(conn, flowObj);
829 conn.endTx(Transaction.COMMIT);
830
831 return true;
832 }
833
834 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800835 * Get a previously added flow.
836 *
837 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800838 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800839 */
840 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800841 public FlowPath getFlow(FlowId flowId) {
842 IFlowPath flowObj = null;
843 try {
844 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
845 != null) {
846 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
847 flowId.toString());
848 } else {
849 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
850 flowId.toString());
851 }
852 } catch (Exception e) {
853 // TODO: handle exceptions
854 conn.endTx(Transaction.ROLLBACK);
855 log.error(":getFlow FlowId:{} failed", flowId.toString());
856 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700857 if (flowObj == null) {
858 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800859 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700860 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800861
862 //
863 // Extract the Flow state
864 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800865 FlowPath flowPath = extractFlowPath(flowObj);
866 conn.endTx(Transaction.COMMIT);
867
868 return flowPath;
869 }
870
871 /**
872 * Get all previously added flows by a specific installer for a given
873 * data path endpoints.
874 *
875 * @param installerId the Caller ID of the installer of the flow to get.
876 * @param dataPathEndpoints the data path endpoints of the flow to get.
877 * @return the Flow Paths if found, otherwise null.
878 */
879 @Override
880 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
881 DataPathEndpoints dataPathEndpoints) {
882 //
883 // TODO: The implementation below is not optimal:
884 // We fetch all flows, and then return only the subset that match
885 // the query conditions.
886 // We should use the appropriate Titan/Gremlin query to filter-out
887 // the flows as appropriate.
888 //
889 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700890 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800891
892 if (allFlows == null) {
893 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700894 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800895 }
896
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800897 for (FlowPath flow : allFlows) {
898 //
899 // TODO: String-based comparison is sub-optimal.
900 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800901 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800902 //
903 if (! flow.installerId().toString().equals(installerId.toString()))
904 continue;
905 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
906 continue;
907 }
908 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
909 continue;
910 }
911 flowPaths.add(flow);
912 }
913
914 if (flowPaths.isEmpty()) {
915 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800916 } else {
917 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
918 }
919
920 return flowPaths;
921 }
922
923 /**
924 * Get all installed flows by all installers for given data path endpoints.
925 *
926 * @param dataPathEndpoints the data path endpoints of the flows to get.
927 * @return the Flow Paths if found, otherwise null.
928 */
929 @Override
930 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
931 //
932 // TODO: The implementation below is not optimal:
933 // We fetch all flows, and then return only the subset that match
934 // the query conditions.
935 // We should use the appropriate Titan/Gremlin query to filter-out
936 // the flows as appropriate.
937 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700938 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
939 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800940
941 if (allFlows == null) {
942 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700943 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800944 }
945
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800946 for (FlowPath flow : allFlows) {
947 //
948 // TODO: String-based comparison is sub-optimal.
949 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800950 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800951 //
952 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
953 continue;
954 }
955 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
956 continue;
957 }
958 flowPaths.add(flow);
959 }
960
961 if (flowPaths.isEmpty()) {
962 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800963 } else {
964 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
965 }
966
967 return flowPaths;
968 }
969
970 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700971 * Get summary of all installed flows by all installers in a given range
972 *
973 * @param flowId the data path endpoints of the flows to get.
974 * @param maxFlows: the maximum number of flows to be returned
975 * @return the Flow Paths if found, otherwise null.
976 */
977 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700978 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700979
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700980 // TODO: The implementation below is not optimal:
981 // We fetch all flows, and then return only the subset that match
982 // the query conditions.
983 // We should use the appropriate Titan/Gremlin query to filter-out
984 // the flows as appropriate.
985 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700986 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700987
Jonathan Hart01f2d272013-04-04 20:03:46 -0700988 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
989
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700990 Collections.sort(flowPathsWithoutFlowEntries,
991 new Comparator<IFlowPath>(){
992 @Override
993 public int compare(IFlowPath first, IFlowPath second) {
994 // TODO Auto-generated method stub
995 long result = new FlowId(first.getFlowId()).value()
996 - new FlowId(second.getFlowId()).value();
997 if (result > 0) return 1;
998 else if (result < 0) return -1;
999 else return 0;
1000 }
1001 }
1002 );
1003
Jonathan Hart01f2d272013-04-04 20:03:46 -07001004 return flowPathsWithoutFlowEntries;
1005
1006 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001007 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001008
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001009 if (allFlows == null) {
1010 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001011 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001012 }
1013
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001014 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001015
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001016 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001017 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001018
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001019 // start from desired flowId
1020 if (flow.flowId().value() < flowId.value()) {
1021 continue;
1022 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001023
1024 // Summarize by making null flow entry fields that are not relevant to report
1025 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1026 flowEntry.setFlowEntryActions(null);
1027 flowEntry.setFlowEntryMatch(null);
1028 }
1029
1030 flowPaths.add(flow);
1031 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1032 break;
1033 }
1034 }
1035
1036 if (flowPaths.isEmpty()) {
1037 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001038 } else {
1039 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1040 }
1041
1042 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001043 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001044 }
1045
1046 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001047 * Get all installed flows by all installers.
1048 *
1049 * @return the Flow Paths if found, otherwise null.
1050 */
1051 @Override
1052 public ArrayList<FlowPath> getAllFlows() {
1053 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001054 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001055
1056 try {
1057 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1058 log.debug("Get all FlowPaths: found FlowPaths");
1059 } else {
1060 log.debug("Get all FlowPaths: no FlowPaths found");
1061 }
1062 } catch (Exception e) {
1063 // TODO: handle exceptions
1064 conn.endTx(Transaction.ROLLBACK);
1065 log.error(":getAllFlowPaths failed");
1066 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001067 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1068 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001069 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001070 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001071
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001072 for (IFlowPath flowObj : flowPathsObj) {
1073 //
1074 // Extract the Flow state
1075 //
1076 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001077 if (flowPath != null)
1078 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001079 }
1080
1081 conn.endTx(Transaction.COMMIT);
1082
1083 return flowPaths;
1084 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001085
1086 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1087 Iterable<IFlowPath> flowPathsObj = null;
1088 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1089 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1090
1091 try {
1092 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1093 log.debug("Get all FlowPaths: found FlowPaths");
1094 } else {
1095 log.debug("Get all FlowPaths: no FlowPaths found");
1096 }
1097 } catch (Exception e) {
1098 // TODO: handle exceptions
1099 conn.endTx(Transaction.ROLLBACK);
1100 log.error(":getAllFlowPaths failed");
1101 }
1102 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1103 return new ArrayList<IFlowPath>(); // No Flows found
1104 }
1105
1106 for (IFlowPath flowObj : flowPathsObj){
1107 flowPathsObjArray.add(flowObj);
1108 }
1109 /*
1110 for (IFlowPath flowObj : flowPathsObj) {
1111 //
1112 // Extract the Flow state
1113 //
1114 FlowPath flowPath = extractFlowPath(flowObj);
1115 if (flowPath != null)
1116 flowPaths.add(flowPath);
1117 }
1118 */
1119
1120 //conn.endTx(Transaction.COMMIT);
1121
1122 return flowPathsObjArray;
1123 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001124
1125 /**
1126 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1127 *
1128 * @param flowObj the object to extract the Flow Path State from.
1129 * @return the extracted Flow Path State.
1130 */
1131 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001132 //
1133 // Extract the Flow state
1134 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001135 String flowIdStr = flowObj.getFlowId();
1136 String installerIdStr = flowObj.getInstallerId();
1137 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001138 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001139 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001140 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001141
1142 if ((flowIdStr == null) ||
1143 (installerIdStr == null) ||
1144 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001145 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001146 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001147 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001148 // TODO: A work-around, becauuse of some bogus database objects
1149 return null;
1150 }
1151
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001152 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001153 flowPath.setFlowId(new FlowId(flowIdStr));
1154 flowPath.setInstallerId(new CallerId(installerIdStr));
1155 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001156 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001157 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001158 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001159 //
1160 // Extract the match conditions common for all Flow Entries
1161 //
1162 {
1163 FlowEntryMatch match = new FlowEntryMatch();
1164 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1165 if (matchEthernetFrameType != null)
1166 match.enableEthernetFrameType(matchEthernetFrameType);
1167 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1168 if (matchSrcIPv4Net != null)
1169 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1170 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1171 if (matchDstIPv4Net != null)
1172 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1173 String matchSrcMac = flowObj.getMatchSrcMac();
1174 if (matchSrcMac != null)
1175 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1176 String matchDstMac = flowObj.getMatchDstMac();
1177 if (matchDstMac != null)
1178 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1179 flowPath.setFlowEntryMatch(match);
1180 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001181
1182 //
1183 // Extract all Flow Entries
1184 //
1185 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1186 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001187 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1188 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001189 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001190 flowPath.dataPath().flowEntries().add(flowEntry);
1191 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001192
1193 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001194 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001195
1196 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001197 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1198 *
1199 * @param flowEntryObj the object to extract the Flow Entry State from.
1200 * @return the extracted Flow Entry State.
1201 */
1202 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1203 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1204 String switchDpidStr = flowEntryObj.getSwitchDpid();
1205 String userState = flowEntryObj.getUserState();
1206 String switchState = flowEntryObj.getSwitchState();
1207
1208 if ((flowEntryIdStr == null) ||
1209 (switchDpidStr == null) ||
1210 (userState == null) ||
1211 (switchState == null)) {
1212 // TODO: A work-around, becauuse of some bogus database objects
1213 return null;
1214 }
1215
1216 FlowEntry flowEntry = new FlowEntry();
1217 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1218 flowEntry.setDpid(new Dpid(switchDpidStr));
1219
1220 //
1221 // Extract the match conditions
1222 //
1223 FlowEntryMatch match = new FlowEntryMatch();
1224 Short matchInPort = flowEntryObj.getMatchInPort();
1225 if (matchInPort != null)
1226 match.enableInPort(new Port(matchInPort));
1227 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1228 if (matchEthernetFrameType != null)
1229 match.enableEthernetFrameType(matchEthernetFrameType);
1230 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1231 if (matchSrcIPv4Net != null)
1232 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1233 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1234 if (matchDstIPv4Net != null)
1235 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1236 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1237 if (matchSrcMac != null)
1238 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1239 String matchDstMac = flowEntryObj.getMatchDstMac();
1240 if (matchDstMac != null)
1241 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1242 flowEntry.setFlowEntryMatch(match);
1243
1244 //
1245 // Extract the actions
1246 //
1247 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1248 Short actionOutputPort = flowEntryObj.getActionOutput();
1249 if (actionOutputPort != null) {
1250 FlowEntryAction action = new FlowEntryAction();
1251 action.setActionOutput(new Port(actionOutputPort));
1252 actions.add(action);
1253 }
1254 flowEntry.setFlowEntryActions(actions);
1255 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1256 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1257 //
1258 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1259 // and FlowEntryErrorState.
1260 //
1261 return flowEntry;
1262 }
1263
1264 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001265 * Add and maintain a shortest-path flow.
1266 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001267 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001268 *
1269 * @param flowPath the Flow Path with the endpoints and the match
1270 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001271 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001272 */
1273 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001274 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001275 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001276 // Don't do the shortest path computation here.
1277 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001278 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001279
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001280 // We need the DataPath to populate the Network MAP
1281 DataPath dataPath = new DataPath();
1282 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1283 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001284
1285 //
1286 // Prepare the computed Flow Path
1287 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001288 FlowPath computedFlowPath = new FlowPath();
1289 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1290 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1291 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001292 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001293
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001294 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001295 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001296 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001297 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001298
1299 // TODO: Mark the flow for maintenance purpose
1300
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001301 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001302 }
1303
1304 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001305 * Reconcile a flow.
1306 *
1307 * @param flowObj the flow that needs to be reconciliated.
1308 * @param newDataPath the new data path to use.
1309 * @return true on success, otherwise false.
1310 */
1311 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1312 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1313
1314 //
1315 // Set the incoming port matching and the outgoing port output
1316 // actions for each flow entry.
1317 //
1318 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1319 // Set the incoming port matching
1320 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1321 flowEntry.setFlowEntryMatch(flowEntryMatch);
1322 flowEntryMatch.enableInPort(flowEntry.inPort());
1323
1324 // Set the outgoing port output action
1325 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1326 if (flowEntryActions == null) {
1327 flowEntryActions = new ArrayList<FlowEntryAction>();
1328 flowEntry.setFlowEntryActions(flowEntryActions);
1329 }
1330 FlowEntryAction flowEntryAction = new FlowEntryAction();
1331 flowEntryAction.setActionOutput(flowEntry.outPort());
1332 flowEntryActions.add(flowEntryAction);
1333 }
1334
1335 //
1336 // Remove the old Flow Entries, and add the new Flow Entries
1337 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001338 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1339 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1340 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001341 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001342 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001343 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001344 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001345 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001346 }
1347
1348 //
1349 // Set the Data Path Summary
1350 //
1351 String dataPathSummaryStr = newDataPath.dataPathSummary();
1352 flowObj.setDataPathSummary(dataPathSummaryStr);
1353
1354 return true;
1355 }
1356
1357 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001358 * Reconcile all flows in a set.
1359 *
1360 * @param flowObjSet the set of flows that need to be reconciliated.
1361 */
1362 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1363 if (! flowObjSet.iterator().hasNext())
1364 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001365 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001366 }
1367
1368 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001369 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001370 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001371 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001372 * @param flowObj the flow path object for the flow entry to install.
1373 * @param flowEntryObj the flow entry object to install.
1374 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001375 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001376 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1377 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001378 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1379 if (flowEntryIdStr == null)
1380 return false;
1381 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001382 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001383 if (userState == null)
1384 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001385
1386 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001387 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001388 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001389 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1390 .getMessage(OFType.FLOW_MOD);
1391 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001392
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001393 short flowModCommand = OFFlowMod.OFPFC_ADD;
1394 if (userState.equals("FE_USER_ADD")) {
1395 flowModCommand = OFFlowMod.OFPFC_ADD;
1396 } else if (userState.equals("FE_USER_MODIFY")) {
1397 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1398 } else if (userState.equals("FE_USER_DELETE")) {
1399 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1400 } else {
1401 // Unknown user state. Ignore the entry
1402 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1403 flowEntryId.toString(), userState);
1404 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001405 }
1406
1407 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001408 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001409 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001410 // NOTE: The Flow matching conditions common for all Flow Entries are
1411 // used ONLY if a Flow Entry does NOT have the corresponding matching
1412 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001413 //
1414 OFMatch match = new OFMatch();
1415 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001416
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001417 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001418 Short matchInPort = flowEntryObj.getMatchInPort();
1419 if (matchInPort != null) {
1420 match.setInputPort(matchInPort);
1421 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1422 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001424 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001425 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1426 if (matchEthernetFrameType == null)
1427 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1428 if (matchEthernetFrameType != null) {
1429 match.setDataLayerType(matchEthernetFrameType);
1430 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1431 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001432
1433 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001434 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1435 if (matchSrcIPv4Net == null)
1436 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1437 if (matchSrcIPv4Net != null) {
1438 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1439 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001440
1441 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001442 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1443 if (matchDstIPv4Net == null)
1444 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1445 if (matchDstIPv4Net != null) {
1446 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1447 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001448
1449 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001450 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1451 if (matchSrcMac == null)
1452 matchSrcMac = flowObj.getMatchSrcMac();
1453 if (matchSrcMac != null) {
1454 match.setDataLayerSource(matchSrcMac);
1455 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1456 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001457
1458 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001459 String matchDstMac = flowEntryObj.getMatchDstMac();
1460 if (matchDstMac == null)
1461 matchDstMac = flowObj.getMatchDstMac();
1462 if (matchDstMac != null) {
1463 match.setDataLayerDestination(matchDstMac);
1464 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1465 }
1466
1467 //
1468 // Fetch the actions
1469 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001470 // TODO: For now we support only the "OUTPUT" actions.
1471 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001472 List<OFAction> actions = new ArrayList<OFAction>();
1473 Short actionOutputPort = flowEntryObj.getActionOutput();
1474 if (actionOutputPort != null) {
1475 OFActionOutput action = new OFActionOutput();
1476 // XXX: The max length is hard-coded for now
1477 action.setMaxLength((short)0xffff);
1478 action.setPort(actionOutputPort);
1479 actions.add(action);
1480 }
1481
1482 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1483 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1484 .setPriority(PRIORITY_DEFAULT)
1485 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1486 .setCookie(cookie)
1487 .setCommand(flowModCommand)
1488 .setMatch(match)
1489 .setActions(actions)
1490 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1491 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1492 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1493 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1494 if (actionOutputPort != null)
1495 fm.setOutPort(actionOutputPort);
1496 }
1497
1498 //
1499 // TODO: Set the following flag
1500 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1501 // See method ForwardingBase::pushRoute()
1502 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001503
1504 //
1505 // Write the message to the switch
1506 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001507 log.debug("MEASUREMENT: Installing flow entry " + userState +
1508 " into switch DPID: " +
1509 mySwitch.getStringId() +
1510 " flowEntryId: " + flowEntryId.toString() +
1511 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1512 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1513 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001514 try {
1515 messageDamper.write(mySwitch, fm, null);
1516 mySwitch.flush();
1517 //
1518 // TODO: We should use the OpenFlow Barrier mechanism
1519 // to check for errors, and update the SwitchState
1520 // for a flow entry after the Barrier message is
1521 // is received.
1522 //
1523 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1524 } catch (IOException e) {
1525 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001526 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001527 }
1528
1529 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001530 }
1531
1532 /**
1533 * Install a Flow Entry on a switch.
1534 *
1535 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001536 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001537 * @param flowEntry the flow entry to install.
1538 * @return true on success, otherwise false.
1539 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001540 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1541 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001542 //
1543 // Create the OpenFlow Flow Modification Entry to push
1544 //
1545 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1546 .getMessage(OFType.FLOW_MOD);
1547 long cookie = flowEntry.flowEntryId().value();
1548
1549 short flowModCommand = OFFlowMod.OFPFC_ADD;
1550 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1551 flowModCommand = OFFlowMod.OFPFC_ADD;
1552 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1553 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1554 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1555 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1556 } else {
1557 // Unknown user state. Ignore the entry
1558 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1559 flowEntry.flowEntryId().toString(),
1560 flowEntry.flowEntryUserState());
1561 return false;
1562 }
1563
1564 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001565 // Fetch the match conditions.
1566 //
1567 // NOTE: The Flow matching conditions common for all Flow Entries are
1568 // used ONLY if a Flow Entry does NOT have the corresponding matching
1569 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001570 //
1571 OFMatch match = new OFMatch();
1572 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001573 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1574 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1575
1576 // Match the Incoming Port
1577 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001578 if (matchInPort != null) {
1579 match.setInputPort(matchInPort.value());
1580 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1581 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001582
1583 // Match the Ethernet Frame Type
1584 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1585 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1586 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1587 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001588 if (matchEthernetFrameType != null) {
1589 match.setDataLayerType(matchEthernetFrameType);
1590 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1591 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001592
1593 // Match the Source IPv4 Network prefix
1594 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1595 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1596 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1597 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001598 if (matchSrcIPv4Net != null) {
1599 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1600 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001601
1602 // Natch the Destination IPv4 Network prefix
1603 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1604 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1605 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1606 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001607 if (matchDstIPv4Net != null) {
1608 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1609 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001610
1611 // Match the Source MAC address
1612 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1613 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1614 matchSrcMac = flowPathMatch.srcMac();
1615 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001616 if (matchSrcMac != null) {
1617 match.setDataLayerSource(matchSrcMac.toString());
1618 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1619 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001620
1621 // Match the Destination MAC address
1622 MACAddress matchDstMac = flowEntryMatch.dstMac();
1623 if ((matchDstMac == null) && (flowPathMatch != null)) {
1624 matchDstMac = flowPathMatch.dstMac();
1625 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001626 if (matchDstMac != null) {
1627 match.setDataLayerDestination(matchDstMac.toString());
1628 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1629 }
1630
1631 //
1632 // Fetch the actions
1633 //
1634 // TODO: For now we support only the "OUTPUT" actions.
1635 //
1636 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1637 List<OFAction> actions = new ArrayList<OFAction>();
1638 ArrayList<FlowEntryAction> flowEntryActions =
1639 flowEntry.flowEntryActions();
1640 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1641 FlowEntryAction.ActionOutput actionOutput =
1642 flowEntryAction.actionOutput();
1643 if (actionOutput != null) {
1644 short actionOutputPort = actionOutput.port().value();
1645 OFActionOutput action = new OFActionOutput();
1646 // XXX: The max length is hard-coded for now
1647 action.setMaxLength((short)0xffff);
1648 action.setPort(actionOutputPort);
1649 actions.add(action);
1650 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1651 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1652 fm.setOutPort(actionOutputPort);
1653 }
1654 }
1655 }
1656
1657 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1658 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1659 .setPriority(PRIORITY_DEFAULT)
1660 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1661 .setCookie(cookie)
1662 .setCommand(flowModCommand)
1663 .setMatch(match)
1664 .setActions(actions)
1665 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1666
1667 //
1668 // TODO: Set the following flag
1669 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1670 // See method ForwardingBase::pushRoute()
1671 //
1672
1673 //
1674 // Write the message to the switch
1675 //
1676 try {
1677 messageDamper.write(mySwitch, fm, null);
1678 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001679 //
1680 // TODO: We should use the OpenFlow Barrier mechanism
1681 // to check for errors, and update the SwitchState
1682 // for a flow entry after the Barrier message is
1683 // is received.
1684 //
1685 // TODO: The FlowEntry Object in Titan should be set
1686 // to FE_SWITCH_UPDATED.
1687 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001688 } catch (IOException e) {
1689 log.error("Failure writing flow mod from network map", e);
1690 return false;
1691 }
1692 return true;
1693 }
1694
1695 /**
1696 * Remove a Flow Entry from a switch.
1697 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001698 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001699 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001700 * @param flowEntry the flow entry to remove.
1701 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001702 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001703 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1704 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001705 //
1706 // The installFlowEntry() method implements both installation
1707 // and removal of flow entries.
1708 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001709 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001710 }
1711
1712 /**
1713 * Install a Flow Entry on a remote controller.
1714 *
1715 * TODO: We need it now: Jono
1716 * - For now it will make a REST call to the remote controller.
1717 * - Internally, it needs to know the name of the remote controller.
1718 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001719 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001720 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001721 * @return true on success, otherwise false.
1722 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001723 public boolean installRemoteFlowEntry(FlowPath flowPath,
1724 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001725 // TODO: We need it now: Jono
1726 // - For now it will make a REST call to the remote controller.
1727 // - Internally, it needs to know the name of the remote controller.
1728 return true;
1729 }
1730
1731 /**
1732 * Remove a flow entry on a remote controller.
1733 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001734 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001735 * @param flowEntry the flow entry to remove.
1736 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001737 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001738 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1739 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001740 //
1741 // The installRemoteFlowEntry() method implements both installation
1742 // and removal of flow entries.
1743 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001744 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001745 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001746}