blob: 4d00443184334d1ac5031b937c40fcaa408f0ebb [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 Radoslavov42f02ba2013-04-03 20:07:30 -0700103 long startTime = System.nanoTime();
104 int counterAllFlowEntries = 0;
105 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700106
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800107 if (floodlightProvider == null) {
108 log.debug("FloodlightProvider service not found!");
109 return;
110 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000111 Map<Long, IOFSwitch> mySwitches =
112 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700113 LinkedList<IFlowEntry> addFlowEntries =
114 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000115 LinkedList<IFlowEntry> deleteFlowEntries =
116 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700117
118 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700119 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700120 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700121 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700122 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000123 Iterable<IFlowEntry> allFlowEntries =
124 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700125 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700126 counterAllFlowEntries++;
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700127 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000128 if ((switchState == null) ||
129 (! switchState.equals("FE_SWITCH_NOT_UPDATED"))) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 continue; // Ignore the entry: nothing to do
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000131 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000132
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000133 String dpidStr = flowEntryObj.getSwitchDpid();
134 if (dpidStr == null)
135 continue;
136 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800137 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000138 if (mySwitch == null)
139 continue; // Ignore the entry: not my switch
140
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700141 IFlowPath flowObj =
142 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
143 if (flowObj == null)
144 continue; // Should NOT happen
145 if (flowObj.getFlowId() == null)
146 continue; // Invalid entry
147
148 //
149 // NOTE: For now we process the DELETE before the ADD
150 // to cover the more common scenario.
151 // TODO: This is error prone and needs to be fixed!
152 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000153 String userState = flowEntryObj.getUserState();
154 if (userState == null)
155 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700156 if (userState.equals("FE_USER_DELETE")) {
157 // An entry that needs to be deleted.
158 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700159 installFlowEntry(mySwitch, flowObj, flowEntryObj);
160 } else {
161 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700162 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700163 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700164 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700165 // TODO: Commented-out for now
166 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700167 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700168 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 processed_measurement_flow = true;
170 }
171 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700172 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700173 }
174
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700175 //
176 // Process the Flow Entries that need to be added
177 //
178 for (IFlowEntry flowEntryObj : addFlowEntries) {
179 IFlowPath flowObj =
180 conn.utils().getFlowPathByFlowEntry(conn,
181 flowEntryObj);
182 if (flowObj == null)
183 continue; // Should NOT happen
184 if (flowObj.getFlowId() == null)
185 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700186
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700187 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700188 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000189 if (mySwitch == null)
190 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700191 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800192 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000193
194 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000195 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700196 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000197 //
198 // TODO: We should use the OpenFlow Barrier mechanism
199 // to check for errors, and delete the Flow Entries after the
200 // Barrier message is received.
201 //
202 while (! deleteFlowEntries.isEmpty()) {
203 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
204 IFlowPath flowObj =
205 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
206 if (flowObj == null) {
207 log.debug("Did not find FlowPath to be deleted");
208 continue;
209 }
210 flowObj.removeFlowEntry(flowEntryObj);
211 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000212 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700213
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700214 conn.endTx(Transaction.COMMIT);
215
216 if (processed_measurement_flow) {
217 long estimatedTime =
218 System.nanoTime() - modifiedMeasurementFlowTime;
219 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
220 (double)estimatedTime / 1000000000 + " sec";
221 log.debug(logMsg);
222 }
223
224 long estimatedTime = System.nanoTime() - startTime;
225 double rate = 0.0;
226 if (estimatedTime > 0)
227 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
228 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
229 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
230 counterMyNotUpdatedFlowEntries + " in " +
231 (double)estimatedTime / 1000000000 + " sec: " +
232 rate + " paths/s";
233 log.debug(logMsg);
234 }
235 };
236
237 final Runnable shortestPathReconcile = new Runnable() {
238 public void run() {
239 long startTime = System.nanoTime();
240 int counterAllFlowPaths = 0;
241 int counterMyFlowPaths = 0;
242
243 if (floodlightProvider == null) {
244 log.debug("FloodlightProvider service not found!");
245 return;
246 }
247 Map<Long, IOFSwitch> mySwitches =
248 floodlightProvider.getSwitches();
249 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
250
251 boolean processed_measurement_flow = false;
252
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700253 //
254 // Fetch and recompute the Shortest Path for those
255 // Flow Paths this controller is responsible for.
256 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700257 topoRouteService.prepareShortestPathTopo();
258 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700259 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700260 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700261 if (flowPathObj == null)
262 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700263
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700264 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000265 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700266 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700267 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700268 //
269 // Use the source DPID as a heuristic to decide
270 // which controller is responsible for maintaining the
271 // shortest path.
272 // NOTE: This heuristic is error-prone: if the switch
273 // goes away and no controller is responsible for that
274 // switch, then the original Flow Path is not cleaned-up
275 //
276 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
277 if (mySwitch == null)
278 continue; // Ignore: not my responsibility
279
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700280 // Test the Data Path Summary string
281 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
282 if (dataPathSummaryStr == null)
283 continue; // Could be invalid entry?
284 if (dataPathSummaryStr.isEmpty())
285 continue; // No need to maintain this flow
286
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000287 //
288 // Test whether we need to complete the Flow cleanup,
289 // if the Flow has been deleted by the user.
290 //
291 String flowUserState = flowPathObj.getUserState();
292 if ((flowUserState != null)
293 && flowUserState.equals("FE_USER_DELETE")) {
294 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
295 boolean empty = true; // TODO: an ugly hack
296 for (IFlowEntry flowEntryObj : flowEntries) {
297 empty = false;
298 break;
299 }
300 if (empty)
301 deleteFlows.add(flowPathObj);
302 }
303
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000304 // Fetch the fields needed to recompute the shortest path
305 Short srcPortShort = flowPathObj.getSrcPort();
306 String dstDpidStr = flowPathObj.getDstSwitch();
307 Short dstPortShort = flowPathObj.getDstPort();
308 if ((srcPortShort == null) ||
309 (dstDpidStr == null) ||
310 (dstPortShort == null)) {
311 continue;
312 }
313
314 Port srcPort = new Port(srcPortShort);
315 Dpid dstDpid = new Dpid(dstDpidStr);
316 Port dstPort = new Port(dstPortShort);
317 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
318 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
319
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700320 counterMyFlowPaths++;
321
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700322 //
323 // NOTE: Using here the regular getShortestPath() method
324 // won't work here, because that method calls internally
325 // "conn.endTx(Transaction.COMMIT)", and that will
326 // invalidate all handlers to the Titan database.
327 // If we want to experiment with calling here
328 // getShortestPath(), we need to refactor that code
329 // to avoid closing the transaction.
330 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700331 DataPath dataPath =
332 topoRouteService.getTopoShortestPath(srcSwitchPort,
333 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000334 if (dataPath == null) {
335 // We need the DataPath to compare the paths
336 dataPath = new DataPath();
337 dataPath.setSrcPort(srcSwitchPort);
338 dataPath.setDstPort(dstSwitchPort);
339 }
340
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700341 String newDataPathSummaryStr = dataPath.dataPathSummary();
342 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
343 continue; // Nothing changed
344
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700345 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700346 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000347
348 //
349 // Delete all leftover Flows marked for deletion from the
350 // Network MAP.
351 //
352 while (! deleteFlows.isEmpty()) {
353 IFlowPath flowPathObj = deleteFlows.poll();
354 conn.utils().removeFlowPath(conn, flowPathObj);
355 }
356
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700357 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700358
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800359 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700360
361 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700362 long estimatedTime =
363 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700364 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
365 (double)estimatedTime / 1000000000 + " sec";
366 log.debug(logMsg);
367 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700368
369 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700370 double rate = 0.0;
371 if (estimatedTime > 0)
372 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700373 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700374 counterAllFlowPaths + " MyFlowPaths: " +
375 counterMyFlowPaths + " in " +
376 (double)estimatedTime / 1000000000 + " sec: " +
377 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700378 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800379 }
380 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700381
Jonathan Hart50a94982013-04-10 14:49:51 -0700382 //final ScheduledFuture<?> mapReaderHandle =
383 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800384
Jonathan Hart50a94982013-04-10 14:49:51 -0700385 //final ScheduledFuture<?> shortestPathReconcileHandle =
386 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700387
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800388 @Override
389 public void init(String conf) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700390 conn = GraphDBConnection.getInstance(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800391 }
392
393 public void finalize() {
394 close();
395 }
396
397 @Override
398 public void close() {
399 conn.close();
400 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800401
402 @Override
403 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
404 Collection<Class<? extends IFloodlightService>> l =
405 new ArrayList<Class<? extends IFloodlightService>>();
406 l.add(IFlowService.class);
407 return l;
408 }
409
410 @Override
411 public Map<Class<? extends IFloodlightService>, IFloodlightService>
412 getServiceImpls() {
413 Map<Class<? extends IFloodlightService>,
414 IFloodlightService> m =
415 new HashMap<Class<? extends IFloodlightService>,
416 IFloodlightService>();
417 m.put(IFlowService.class, this);
418 return m;
419 }
420
421 @Override
422 public Collection<Class<? extends IFloodlightService>>
423 getModuleDependencies() {
424 Collection<Class<? extends IFloodlightService>> l =
425 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800426 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700427 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800428 l.add(IRestApiService.class);
429 return l;
430 }
431
432 @Override
433 public void init(FloodlightModuleContext context)
434 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700435 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800436 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700437 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800438 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
440 EnumSet.of(OFType.FLOW_MOD),
441 OFMESSAGE_DAMPER_TIMEOUT);
442 // TODO: An ugly hack!
443 String conf = "/tmp/cassandra.titan";
444 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700445
446 mapReaderScheduler = Executors.newScheduledThreadPool(1);
447 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800448 }
449
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000450 private long getNextFlowEntryId() {
451 //
452 // Generate the next Flow Entry ID.
453 // NOTE: For now, the higher 32 bits are random, and
454 // the lower 32 bits are sequential.
455 // In the future, we need a better allocation mechanism.
456 //
457 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
458 nextFlowEntryIdPrefix = randomGenerator.nextInt();
459 nextFlowEntryIdSuffix = 0;
460 } else {
461 nextFlowEntryIdSuffix++;
462 }
463 long result = (long)nextFlowEntryIdPrefix << 32;
464 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
465 return result;
466 }
467
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800468 @Override
469 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700470 restApi.addRestletRoutable(new FlowWebRoutable());
471
472 // Initialize the Flow Entry ID generator
473 nextFlowEntryIdPrefix = randomGenerator.nextInt();
474
475 mapReaderScheduler.scheduleAtFixedRate(
476 mapReader, 3, 3, TimeUnit.SECONDS);
477 shortestPathReconcileScheduler.scheduleAtFixedRate(
478 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800479 }
480
481 /**
482 * Add a flow.
483 *
484 * Internally, ONOS will automatically register the installer for
485 * receiving Flow Path Notifications for that path.
486 *
487 * @param flowPath the Flow Path to install.
488 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700489 * @param dataPathSummaryStr the data path summary string if the added
490 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800491 * @return true on success, otherwise false.
492 */
493 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700494 public boolean addFlow(FlowPath flowPath, FlowId flowId,
495 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700496 /*
497 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700498 if (flowPath.flowId().value() == measurementFlowId) {
499 modifiedMeasurementFlowTime = System.nanoTime();
500 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700501 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800502
503 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000504 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800505 try {
506 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
507 != null) {
508 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
509 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000510 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800511 } else {
512 flowObj = conn.utils().newFlowPath(conn);
513 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
514 flowPath.flowId().toString());
515 }
516 } catch (Exception e) {
517 // TODO: handle exceptions
518 conn.endTx(Transaction.ROLLBACK);
519 log.error(":addFlow FlowId:{} failed",
520 flowPath.flowId().toString());
521 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700522 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000523 log.error(":addFlow FlowId:{} failed: Flow object not created",
524 flowPath.flowId().toString());
525 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800526 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700527 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800528
529 //
530 // Set the Flow key:
531 // - flowId
532 //
533 flowObj.setFlowId(flowPath.flowId().toString());
534 flowObj.setType("flow");
535
536 //
537 // Set the Flow attributes:
538 // - flowPath.installerId()
539 // - flowPath.dataPath().srcPort()
540 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700541 // - flowPath.matchEthernetFrameType()
542 // - flowPath.matchSrcIPv4Net()
543 // - flowPath.matchDstIPv4Net()
544 // - flowPath.matchSrcMac()
545 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800546 //
547 flowObj.setInstallerId(flowPath.installerId().toString());
548 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
549 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
550 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
551 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700552 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
553 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
554 }
555 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
556 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
557 }
558 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
559 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
560 }
561 if (flowPath.flowEntryMatch().matchSrcMac()) {
562 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
563 }
564 if (flowPath.flowEntryMatch().matchDstMac()) {
565 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
566 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800567
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700568 if (dataPathSummaryStr != null) {
569 flowObj.setDataPathSummary(dataPathSummaryStr);
570 } else {
571 flowObj.setDataPathSummary("");
572 }
573
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000574 if (found)
575 flowObj.setUserState("FE_USER_MODIFY");
576 else
577 flowObj.setUserState("FE_USER_ADD");
578
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800579 // Flow edges:
580 // HeadFE
581
582
583 //
584 // Flow Entries:
585 // flowPath.dataPath().flowEntries()
586 //
587 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700588 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000589 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800590 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700591 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800592 }
593 conn.endTx(Transaction.COMMIT);
594
595 //
596 // TODO: We need a proper Flow ID allocation mechanism.
597 //
598 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700599
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800600 return true;
601 }
602
603 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700604 * Add a flow entry to the Network MAP.
605 *
606 * @param flowObj the corresponding Flow Path object for the Flow Entry.
607 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700608 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700609 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700610 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700611 // Flow edges
612 // HeadFE (TODO)
613
614 //
615 // Assign the FlowEntry ID.
616 //
617 if ((flowEntry.flowEntryId() == null) ||
618 (flowEntry.flowEntryId().value() == 0)) {
619 long id = getNextFlowEntryId();
620 flowEntry.setFlowEntryId(new FlowEntryId(id));
621 }
622
623 IFlowEntry flowEntryObj = null;
624 boolean found = false;
625 try {
626 if ((flowEntryObj =
627 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
628 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
629 flowEntry.flowEntryId().toString());
630 found = true;
631 } else {
632 flowEntryObj = conn.utils().newFlowEntry(conn);
633 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
634 flowEntry.flowEntryId().toString());
635 }
636 } catch (Exception e) {
637 log.error(":addFlow FlowEntryId:{} failed",
638 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700639 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700640 }
641 if (flowEntryObj == null) {
642 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
643 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700644 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700645 }
646
647 //
648 // Set the Flow Entry key:
649 // - flowEntry.flowEntryId()
650 //
651 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
652 flowEntryObj.setType("flow_entry");
653
654 //
655 // Set the Flow Entry Edges and attributes:
656 // - Switch edge
657 // - InPort edge
658 // - OutPort edge
659 //
660 // - flowEntry.flowEntryMatch()
661 // - flowEntry.flowEntryActions()
662 // - flowEntry.dpid()
663 // - flowEntry.flowEntryUserState()
664 // - flowEntry.flowEntrySwitchState()
665 // - flowEntry.flowEntryErrorState()
666 // - flowEntry.matchInPort()
667 // - flowEntry.matchEthernetFrameType()
668 // - flowEntry.matchSrcIPv4Net()
669 // - flowEntry.matchDstIPv4Net()
670 // - flowEntry.matchSrcMac()
671 // - flowEntry.matchDstMac()
672 // - flowEntry.actionOutput()
673 //
674 ISwitchObject sw =
675 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
676 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
677 flowEntryObj.setSwitch(sw);
678 if (flowEntry.flowEntryMatch().matchInPort()) {
679 IPortObject inport =
680 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
681 flowEntry.flowEntryMatch().inPort().value());
682 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
683 flowEntryObj.setInPort(inport);
684 }
685 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
686 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
687 }
688 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
689 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
690 }
691 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
692 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
693 }
694 if (flowEntry.flowEntryMatch().matchSrcMac()) {
695 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
696 }
697 if (flowEntry.flowEntryMatch().matchDstMac()) {
698 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
699 }
700
701 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
702 if (fa.actionOutput() != null) {
703 IPortObject outport =
704 conn.utils().searchPort(conn,
705 flowEntry.dpid().toString(),
706 fa.actionOutput().port().value());
707 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
708 flowEntryObj.setOutPort(outport);
709 }
710 }
711 // TODO: Hacks with hard-coded state names!
712 if (found)
713 flowEntryObj.setUserState("FE_USER_MODIFY");
714 else
715 flowEntryObj.setUserState("FE_USER_ADD");
716 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
717 //
718 // TODO: Take care of the FlowEntryErrorState.
719 //
720
721 // Flow Entries edges:
722 // Flow
723 // NextFE (TODO)
724 if (! found) {
725 flowObj.addFlowEntry(flowEntryObj);
726 flowEntryObj.setFlow(flowObj);
727 }
728
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700729 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700730 }
731
732 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800733 * Delete a previously added flow.
734 *
735 * @param flowId the Flow ID of the flow to delete.
736 * @return true on success, otherwise false.
737 */
738 @Override
739 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700740 /*
741 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700742 if (flowId.value() == measurementFlowId) {
743 modifiedMeasurementFlowTime = System.nanoTime();
744 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700745 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700746
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800747 IFlowPath flowObj = null;
748 //
749 // We just mark the entries for deletion,
750 // and let the switches remove each individual entry after
751 // it has been removed from the switches.
752 //
753 try {
754 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
755 != null) {
756 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
757 flowId.toString());
758 } else {
759 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
760 flowId.toString());
761 }
762 } catch (Exception e) {
763 // TODO: handle exceptions
764 conn.endTx(Transaction.ROLLBACK);
765 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
766 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700767 if (flowObj == null) {
768 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800769 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700770 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800771
772 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000773 // Find and mark for deletion all Flow Entries,
774 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800775 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000776 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800777 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
778 boolean empty = true; // TODO: an ugly hack
779 for (IFlowEntry flowEntryObj : flowEntries) {
780 empty = false;
781 // flowObj.removeFlowEntry(flowEntryObj);
782 // conn.utils().removeFlowEntry(conn, flowEntryObj);
783 flowEntryObj.setUserState("FE_USER_DELETE");
784 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
785 }
786 // Remove from the database empty flows
787 if (empty)
788 conn.utils().removeFlowPath(conn, flowObj);
789 conn.endTx(Transaction.COMMIT);
790
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800791 return true;
792 }
793
794 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700795 * Clear the state for a previously added flow.
796 *
797 * @param flowId the Flow ID of the flow to clear.
798 * @return true on success, otherwise false.
799 */
800 @Override
801 public boolean clearFlow(FlowId flowId) {
802 IFlowPath flowObj = null;
803 try {
804 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
805 != null) {
806 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
807 flowId.toString());
808 } else {
809 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
810 flowId.toString());
811 }
812 } catch (Exception e) {
813 // TODO: handle exceptions
814 conn.endTx(Transaction.ROLLBACK);
815 log.error(":clearFlow FlowId:{} failed", flowId.toString());
816 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700817 if (flowObj == null) {
818 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700819 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700820 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700821
822 //
823 // Remove all Flow Entries
824 //
825 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
826 for (IFlowEntry flowEntryObj : flowEntries) {
827 flowObj.removeFlowEntry(flowEntryObj);
828 conn.utils().removeFlowEntry(conn, flowEntryObj);
829 }
830 // Remove the Flow itself
831 conn.utils().removeFlowPath(conn, flowObj);
832 conn.endTx(Transaction.COMMIT);
833
834 return true;
835 }
836
837 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800838 * Get a previously added flow.
839 *
840 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800841 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800842 */
843 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800844 public FlowPath getFlow(FlowId flowId) {
845 IFlowPath flowObj = null;
846 try {
847 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
848 != null) {
849 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
850 flowId.toString());
851 } else {
852 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
853 flowId.toString());
854 }
855 } catch (Exception e) {
856 // TODO: handle exceptions
857 conn.endTx(Transaction.ROLLBACK);
858 log.error(":getFlow FlowId:{} failed", flowId.toString());
859 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700860 if (flowObj == null) {
861 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800862 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700863 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800864
865 //
866 // Extract the Flow state
867 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800868 FlowPath flowPath = extractFlowPath(flowObj);
869 conn.endTx(Transaction.COMMIT);
870
871 return flowPath;
872 }
873
874 /**
875 * Get all previously added flows by a specific installer for a given
876 * data path endpoints.
877 *
878 * @param installerId the Caller ID of the installer of the flow to get.
879 * @param dataPathEndpoints the data path endpoints of the flow to get.
880 * @return the Flow Paths if found, otherwise null.
881 */
882 @Override
883 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
884 DataPathEndpoints dataPathEndpoints) {
885 //
886 // TODO: The implementation below is not optimal:
887 // We fetch all flows, and then return only the subset that match
888 // the query conditions.
889 // We should use the appropriate Titan/Gremlin query to filter-out
890 // the flows as appropriate.
891 //
892 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700893 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800894
895 if (allFlows == null) {
896 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700897 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800898 }
899
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800900 for (FlowPath flow : allFlows) {
901 //
902 // TODO: String-based comparison is sub-optimal.
903 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800904 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800905 //
906 if (! flow.installerId().toString().equals(installerId.toString()))
907 continue;
908 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
909 continue;
910 }
911 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
912 continue;
913 }
914 flowPaths.add(flow);
915 }
916
917 if (flowPaths.isEmpty()) {
918 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800919 } else {
920 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
921 }
922
923 return flowPaths;
924 }
925
926 /**
927 * Get all installed flows by all installers for given data path endpoints.
928 *
929 * @param dataPathEndpoints the data path endpoints of the flows to get.
930 * @return the Flow Paths if found, otherwise null.
931 */
932 @Override
933 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
934 //
935 // TODO: The implementation below is not optimal:
936 // We fetch all flows, and then return only the subset that match
937 // the query conditions.
938 // We should use the appropriate Titan/Gremlin query to filter-out
939 // the flows as appropriate.
940 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700941 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
942 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800943
944 if (allFlows == null) {
945 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700946 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800947 }
948
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800949 for (FlowPath flow : allFlows) {
950 //
951 // TODO: String-based comparison is sub-optimal.
952 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800953 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800954 //
955 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
956 continue;
957 }
958 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
959 continue;
960 }
961 flowPaths.add(flow);
962 }
963
964 if (flowPaths.isEmpty()) {
965 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800966 } else {
967 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
968 }
969
970 return flowPaths;
971 }
972
973 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700974 * Get summary of all installed flows by all installers in a given range
975 *
976 * @param flowId the data path endpoints of the flows to get.
977 * @param maxFlows: the maximum number of flows to be returned
978 * @return the Flow Paths if found, otherwise null.
979 */
980 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700981 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700982
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700983 // TODO: The implementation below is not optimal:
984 // We fetch all flows, and then return only the subset that match
985 // the query conditions.
986 // We should use the appropriate Titan/Gremlin query to filter-out
987 // the flows as appropriate.
988 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700989 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700990
Jonathan Hart01f2d272013-04-04 20:03:46 -0700991 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
992
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700993 Collections.sort(flowPathsWithoutFlowEntries,
994 new Comparator<IFlowPath>(){
995 @Override
996 public int compare(IFlowPath first, IFlowPath second) {
997 // TODO Auto-generated method stub
998 long result = new FlowId(first.getFlowId()).value()
999 - new FlowId(second.getFlowId()).value();
1000 if (result > 0) return 1;
1001 else if (result < 0) return -1;
1002 else return 0;
1003 }
1004 }
1005 );
1006
Jonathan Hart01f2d272013-04-04 20:03:46 -07001007 return flowPathsWithoutFlowEntries;
1008
1009 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001010 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001011
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001012 if (allFlows == null) {
1013 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001014 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001015 }
1016
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001017 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001018
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001019 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001020 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001021
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001022 // start from desired flowId
1023 if (flow.flowId().value() < flowId.value()) {
1024 continue;
1025 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001026
1027 // Summarize by making null flow entry fields that are not relevant to report
1028 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1029 flowEntry.setFlowEntryActions(null);
1030 flowEntry.setFlowEntryMatch(null);
1031 }
1032
1033 flowPaths.add(flow);
1034 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1035 break;
1036 }
1037 }
1038
1039 if (flowPaths.isEmpty()) {
1040 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001041 } else {
1042 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1043 }
1044
1045 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001046 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001047 }
1048
1049 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001050 * Get all installed flows by all installers.
1051 *
1052 * @return the Flow Paths if found, otherwise null.
1053 */
1054 @Override
1055 public ArrayList<FlowPath> getAllFlows() {
1056 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001057 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001058
1059 try {
1060 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1061 log.debug("Get all FlowPaths: found FlowPaths");
1062 } else {
1063 log.debug("Get all FlowPaths: no FlowPaths found");
1064 }
1065 } catch (Exception e) {
1066 // TODO: handle exceptions
1067 conn.endTx(Transaction.ROLLBACK);
1068 log.error(":getAllFlowPaths failed");
1069 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001070 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1071 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001072 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001073 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001074
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001075 for (IFlowPath flowObj : flowPathsObj) {
1076 //
1077 // Extract the Flow state
1078 //
1079 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001080 if (flowPath != null)
1081 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001082 }
1083
1084 conn.endTx(Transaction.COMMIT);
1085
1086 return flowPaths;
1087 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001088
1089 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1090 Iterable<IFlowPath> flowPathsObj = null;
1091 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1092 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1093
1094 try {
1095 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1096 log.debug("Get all FlowPaths: found FlowPaths");
1097 } else {
1098 log.debug("Get all FlowPaths: no FlowPaths found");
1099 }
1100 } catch (Exception e) {
1101 // TODO: handle exceptions
1102 conn.endTx(Transaction.ROLLBACK);
1103 log.error(":getAllFlowPaths failed");
1104 }
1105 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1106 return new ArrayList<IFlowPath>(); // No Flows found
1107 }
1108
1109 for (IFlowPath flowObj : flowPathsObj){
1110 flowPathsObjArray.add(flowObj);
1111 }
1112 /*
1113 for (IFlowPath flowObj : flowPathsObj) {
1114 //
1115 // Extract the Flow state
1116 //
1117 FlowPath flowPath = extractFlowPath(flowObj);
1118 if (flowPath != null)
1119 flowPaths.add(flowPath);
1120 }
1121 */
1122
1123 //conn.endTx(Transaction.COMMIT);
1124
1125 return flowPathsObjArray;
1126 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001127
1128 /**
1129 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1130 *
1131 * @param flowObj the object to extract the Flow Path State from.
1132 * @return the extracted Flow Path State.
1133 */
1134 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001135 //
1136 // Extract the Flow state
1137 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001138 String flowIdStr = flowObj.getFlowId();
1139 String installerIdStr = flowObj.getInstallerId();
1140 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001141 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001142 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001143 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001144
1145 if ((flowIdStr == null) ||
1146 (installerIdStr == null) ||
1147 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001148 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001149 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001150 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001151 // TODO: A work-around, becauuse of some bogus database objects
1152 return null;
1153 }
1154
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001155 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001156 flowPath.setFlowId(new FlowId(flowIdStr));
1157 flowPath.setInstallerId(new CallerId(installerIdStr));
1158 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001159 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001160 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001161 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001162 //
1163 // Extract the match conditions common for all Flow Entries
1164 //
1165 {
1166 FlowEntryMatch match = new FlowEntryMatch();
1167 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1168 if (matchEthernetFrameType != null)
1169 match.enableEthernetFrameType(matchEthernetFrameType);
1170 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1171 if (matchSrcIPv4Net != null)
1172 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1173 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1174 if (matchDstIPv4Net != null)
1175 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1176 String matchSrcMac = flowObj.getMatchSrcMac();
1177 if (matchSrcMac != null)
1178 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1179 String matchDstMac = flowObj.getMatchDstMac();
1180 if (matchDstMac != null)
1181 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1182 flowPath.setFlowEntryMatch(match);
1183 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001184
1185 //
1186 // Extract all Flow Entries
1187 //
1188 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1189 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001190 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1191 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001192 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001193 flowPath.dataPath().flowEntries().add(flowEntry);
1194 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001195
1196 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001197 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001198
1199 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001200 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1201 *
1202 * @param flowEntryObj the object to extract the Flow Entry State from.
1203 * @return the extracted Flow Entry State.
1204 */
1205 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1206 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1207 String switchDpidStr = flowEntryObj.getSwitchDpid();
1208 String userState = flowEntryObj.getUserState();
1209 String switchState = flowEntryObj.getSwitchState();
1210
1211 if ((flowEntryIdStr == null) ||
1212 (switchDpidStr == null) ||
1213 (userState == null) ||
1214 (switchState == null)) {
1215 // TODO: A work-around, becauuse of some bogus database objects
1216 return null;
1217 }
1218
1219 FlowEntry flowEntry = new FlowEntry();
1220 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1221 flowEntry.setDpid(new Dpid(switchDpidStr));
1222
1223 //
1224 // Extract the match conditions
1225 //
1226 FlowEntryMatch match = new FlowEntryMatch();
1227 Short matchInPort = flowEntryObj.getMatchInPort();
1228 if (matchInPort != null)
1229 match.enableInPort(new Port(matchInPort));
1230 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1231 if (matchEthernetFrameType != null)
1232 match.enableEthernetFrameType(matchEthernetFrameType);
1233 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1234 if (matchSrcIPv4Net != null)
1235 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1236 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1237 if (matchDstIPv4Net != null)
1238 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1239 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1240 if (matchSrcMac != null)
1241 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1242 String matchDstMac = flowEntryObj.getMatchDstMac();
1243 if (matchDstMac != null)
1244 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1245 flowEntry.setFlowEntryMatch(match);
1246
1247 //
1248 // Extract the actions
1249 //
1250 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1251 Short actionOutputPort = flowEntryObj.getActionOutput();
1252 if (actionOutputPort != null) {
1253 FlowEntryAction action = new FlowEntryAction();
1254 action.setActionOutput(new Port(actionOutputPort));
1255 actions.add(action);
1256 }
1257 flowEntry.setFlowEntryActions(actions);
1258 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1259 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1260 //
1261 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1262 // and FlowEntryErrorState.
1263 //
1264 return flowEntry;
1265 }
1266
1267 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001268 * Add and maintain a shortest-path flow.
1269 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001270 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001271 *
1272 * @param flowPath the Flow Path with the endpoints and the match
1273 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001274 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001275 */
1276 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001277 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001278 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001279 // Don't do the shortest path computation here.
1280 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001281 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001282
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001283 // We need the DataPath to populate the Network MAP
1284 DataPath dataPath = new DataPath();
1285 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1286 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001287
1288 //
1289 // Prepare the computed Flow Path
1290 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001291 FlowPath computedFlowPath = new FlowPath();
1292 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1293 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1294 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001295 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001296
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001297 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001298 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001299 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001300 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001301
1302 // TODO: Mark the flow for maintenance purpose
1303
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001304 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001305 }
1306
1307 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001308 * Reconcile a flow.
1309 *
1310 * @param flowObj the flow that needs to be reconciliated.
1311 * @param newDataPath the new data path to use.
1312 * @return true on success, otherwise false.
1313 */
1314 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1315 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1316
1317 //
1318 // Set the incoming port matching and the outgoing port output
1319 // actions for each flow entry.
1320 //
1321 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1322 // Set the incoming port matching
1323 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1324 flowEntry.setFlowEntryMatch(flowEntryMatch);
1325 flowEntryMatch.enableInPort(flowEntry.inPort());
1326
1327 // Set the outgoing port output action
1328 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1329 if (flowEntryActions == null) {
1330 flowEntryActions = new ArrayList<FlowEntryAction>();
1331 flowEntry.setFlowEntryActions(flowEntryActions);
1332 }
1333 FlowEntryAction flowEntryAction = new FlowEntryAction();
1334 flowEntryAction.setActionOutput(flowEntry.outPort());
1335 flowEntryActions.add(flowEntryAction);
1336 }
1337
1338 //
1339 // Remove the old Flow Entries, and add the new Flow Entries
1340 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001341 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1342 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1343 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001344 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001345 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001346 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001347 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001348 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001349 }
1350
1351 //
1352 // Set the Data Path Summary
1353 //
1354 String dataPathSummaryStr = newDataPath.dataPathSummary();
1355 flowObj.setDataPathSummary(dataPathSummaryStr);
1356
1357 return true;
1358 }
1359
1360 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001361 * Reconcile all flows in a set.
1362 *
1363 * @param flowObjSet the set of flows that need to be reconciliated.
1364 */
1365 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1366 if (! flowObjSet.iterator().hasNext())
1367 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001368 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001369 }
1370
1371 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001372 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001373 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001374 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001375 * @param flowObj the flow path object for the flow entry to install.
1376 * @param flowEntryObj the flow entry object to install.
1377 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001378 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001379 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1380 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001381 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1382 if (flowEntryIdStr == null)
1383 return false;
1384 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001385 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001386 if (userState == null)
1387 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001388
1389 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001390 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001391 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001392 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1393 .getMessage(OFType.FLOW_MOD);
1394 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001395
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001396 short flowModCommand = OFFlowMod.OFPFC_ADD;
1397 if (userState.equals("FE_USER_ADD")) {
1398 flowModCommand = OFFlowMod.OFPFC_ADD;
1399 } else if (userState.equals("FE_USER_MODIFY")) {
1400 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1401 } else if (userState.equals("FE_USER_DELETE")) {
1402 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1403 } else {
1404 // Unknown user state. Ignore the entry
1405 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1406 flowEntryId.toString(), userState);
1407 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001408 }
1409
1410 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001411 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001412 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001413 // NOTE: The Flow matching conditions common for all Flow Entries are
1414 // used ONLY if a Flow Entry does NOT have the corresponding matching
1415 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001416 //
1417 OFMatch match = new OFMatch();
1418 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001419
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001420 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001421 Short matchInPort = flowEntryObj.getMatchInPort();
1422 if (matchInPort != null) {
1423 match.setInputPort(matchInPort);
1424 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1425 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001426
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001427 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001428 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1429 if (matchEthernetFrameType == null)
1430 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1431 if (matchEthernetFrameType != null) {
1432 match.setDataLayerType(matchEthernetFrameType);
1433 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1434 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001435
1436 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001437 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1438 if (matchSrcIPv4Net == null)
1439 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1440 if (matchSrcIPv4Net != null) {
1441 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1442 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001443
1444 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001445 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1446 if (matchDstIPv4Net == null)
1447 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1448 if (matchDstIPv4Net != null) {
1449 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1450 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001451
1452 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001453 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1454 if (matchSrcMac == null)
1455 matchSrcMac = flowObj.getMatchSrcMac();
1456 if (matchSrcMac != null) {
1457 match.setDataLayerSource(matchSrcMac);
1458 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1459 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001460
1461 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001462 String matchDstMac = flowEntryObj.getMatchDstMac();
1463 if (matchDstMac == null)
1464 matchDstMac = flowObj.getMatchDstMac();
1465 if (matchDstMac != null) {
1466 match.setDataLayerDestination(matchDstMac);
1467 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1468 }
1469
1470 //
1471 // Fetch the actions
1472 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001473 // TODO: For now we support only the "OUTPUT" actions.
1474 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001475 List<OFAction> actions = new ArrayList<OFAction>();
1476 Short actionOutputPort = flowEntryObj.getActionOutput();
1477 if (actionOutputPort != null) {
1478 OFActionOutput action = new OFActionOutput();
1479 // XXX: The max length is hard-coded for now
1480 action.setMaxLength((short)0xffff);
1481 action.setPort(actionOutputPort);
1482 actions.add(action);
1483 }
1484
1485 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1486 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1487 .setPriority(PRIORITY_DEFAULT)
1488 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1489 .setCookie(cookie)
1490 .setCommand(flowModCommand)
1491 .setMatch(match)
1492 .setActions(actions)
1493 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1494 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1495 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1496 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1497 if (actionOutputPort != null)
1498 fm.setOutPort(actionOutputPort);
1499 }
1500
1501 //
1502 // TODO: Set the following flag
1503 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1504 // See method ForwardingBase::pushRoute()
1505 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001506
1507 //
1508 // Write the message to the switch
1509 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001510 log.debug("MEASUREMENT: Installing flow entry " + userState +
1511 " into switch DPID: " +
1512 mySwitch.getStringId() +
1513 " flowEntryId: " + flowEntryId.toString() +
1514 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1515 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1516 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001517 try {
1518 messageDamper.write(mySwitch, fm, null);
1519 mySwitch.flush();
1520 //
1521 // TODO: We should use the OpenFlow Barrier mechanism
1522 // to check for errors, and update the SwitchState
1523 // for a flow entry after the Barrier message is
1524 // is received.
1525 //
1526 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1527 } catch (IOException e) {
1528 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001529 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001530 }
1531
1532 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001533 }
1534
1535 /**
1536 * Install a Flow Entry on a switch.
1537 *
1538 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001539 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001540 * @param flowEntry the flow entry to install.
1541 * @return true on success, otherwise false.
1542 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001543 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1544 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001545 //
1546 // Create the OpenFlow Flow Modification Entry to push
1547 //
1548 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1549 .getMessage(OFType.FLOW_MOD);
1550 long cookie = flowEntry.flowEntryId().value();
1551
1552 short flowModCommand = OFFlowMod.OFPFC_ADD;
1553 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1554 flowModCommand = OFFlowMod.OFPFC_ADD;
1555 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1556 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1557 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1558 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1559 } else {
1560 // Unknown user state. Ignore the entry
1561 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1562 flowEntry.flowEntryId().toString(),
1563 flowEntry.flowEntryUserState());
1564 return false;
1565 }
1566
1567 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001568 // Fetch the match conditions.
1569 //
1570 // NOTE: The Flow matching conditions common for all Flow Entries are
1571 // used ONLY if a Flow Entry does NOT have the corresponding matching
1572 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001573 //
1574 OFMatch match = new OFMatch();
1575 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001576 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1577 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1578
1579 // Match the Incoming Port
1580 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001581 if (matchInPort != null) {
1582 match.setInputPort(matchInPort.value());
1583 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1584 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001585
1586 // Match the Ethernet Frame Type
1587 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1588 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1589 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1590 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001591 if (matchEthernetFrameType != null) {
1592 match.setDataLayerType(matchEthernetFrameType);
1593 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1594 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001595
1596 // Match the Source IPv4 Network prefix
1597 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1598 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1599 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1600 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001601 if (matchSrcIPv4Net != null) {
1602 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1603 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001604
1605 // Natch the Destination IPv4 Network prefix
1606 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1607 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1608 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1609 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001610 if (matchDstIPv4Net != null) {
1611 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1612 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001613
1614 // Match the Source MAC address
1615 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1616 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1617 matchSrcMac = flowPathMatch.srcMac();
1618 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001619 if (matchSrcMac != null) {
1620 match.setDataLayerSource(matchSrcMac.toString());
1621 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1622 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001623
1624 // Match the Destination MAC address
1625 MACAddress matchDstMac = flowEntryMatch.dstMac();
1626 if ((matchDstMac == null) && (flowPathMatch != null)) {
1627 matchDstMac = flowPathMatch.dstMac();
1628 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001629 if (matchDstMac != null) {
1630 match.setDataLayerDestination(matchDstMac.toString());
1631 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1632 }
1633
1634 //
1635 // Fetch the actions
1636 //
1637 // TODO: For now we support only the "OUTPUT" actions.
1638 //
1639 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1640 List<OFAction> actions = new ArrayList<OFAction>();
1641 ArrayList<FlowEntryAction> flowEntryActions =
1642 flowEntry.flowEntryActions();
1643 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1644 FlowEntryAction.ActionOutput actionOutput =
1645 flowEntryAction.actionOutput();
1646 if (actionOutput != null) {
1647 short actionOutputPort = actionOutput.port().value();
1648 OFActionOutput action = new OFActionOutput();
1649 // XXX: The max length is hard-coded for now
1650 action.setMaxLength((short)0xffff);
1651 action.setPort(actionOutputPort);
1652 actions.add(action);
1653 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1654 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1655 fm.setOutPort(actionOutputPort);
1656 }
1657 }
1658 }
1659
1660 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1661 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1662 .setPriority(PRIORITY_DEFAULT)
1663 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1664 .setCookie(cookie)
1665 .setCommand(flowModCommand)
1666 .setMatch(match)
1667 .setActions(actions)
1668 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1669
1670 //
1671 // TODO: Set the following flag
1672 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1673 // See method ForwardingBase::pushRoute()
1674 //
1675
1676 //
1677 // Write the message to the switch
1678 //
1679 try {
1680 messageDamper.write(mySwitch, fm, null);
1681 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001682 //
1683 // TODO: We should use the OpenFlow Barrier mechanism
1684 // to check for errors, and update the SwitchState
1685 // for a flow entry after the Barrier message is
1686 // is received.
1687 //
1688 // TODO: The FlowEntry Object in Titan should be set
1689 // to FE_SWITCH_UPDATED.
1690 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001691 } catch (IOException e) {
1692 log.error("Failure writing flow mod from network map", e);
1693 return false;
1694 }
1695 return true;
1696 }
1697
1698 /**
1699 * Remove a Flow Entry from a switch.
1700 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001701 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001702 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001703 * @param flowEntry the flow entry to remove.
1704 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001705 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001706 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1707 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001708 //
1709 // The installFlowEntry() method implements both installation
1710 // and removal of flow entries.
1711 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001712 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001713 }
1714
1715 /**
1716 * Install a Flow Entry on a remote controller.
1717 *
1718 * TODO: We need it now: Jono
1719 * - For now it will make a REST call to the remote controller.
1720 * - Internally, it needs to know the name of the remote controller.
1721 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001722 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001723 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001724 * @return true on success, otherwise false.
1725 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001726 public boolean installRemoteFlowEntry(FlowPath flowPath,
1727 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001728 // TODO: We need it now: Jono
1729 // - For now it will make a REST call to the remote controller.
1730 // - Internally, it needs to know the name of the remote controller.
1731 return true;
1732 }
1733
1734 /**
1735 * Remove a flow entry on a remote controller.
1736 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001737 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001738 * @param flowEntry the flow entry to remove.
1739 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001740 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001741 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1742 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001743 //
1744 // The installRemoteFlowEntry() method implements both installation
1745 // and removal of flow entries.
1746 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001747 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001748 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001749}