blob: 59e6f469b8d75698b7969db65228b79822e8cfcc [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07006import java.util.Collections;
7import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000010import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000013import java.util.Random;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
15import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080017
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import net.floodlightcontroller.core.IFloodlightProviderService;
19import net.floodlightcontroller.core.INetMapStorage;
20import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
21import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070022import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070023import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070024import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080025import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080030import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
31import net.floodlightcontroller.restserver.IRestApiService;
32import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080034import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070035import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070037import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070039import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080040import net.floodlightcontroller.util.FlowEntrySwitchState;
41import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080042import net.floodlightcontroller.util.FlowId;
43import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.IPv4Net;
45import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.OFMessageDamper;
47import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070048import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.onrc.onos.util.GraphDBConnection;
50import net.onrc.onos.util.GraphDBConnection.Transaction;
51
52import org.openflow.protocol.OFFlowMod;
53import org.openflow.protocol.OFMatch;
54import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070055import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import org.openflow.protocol.OFType;
57import org.openflow.protocol.action.OFAction;
58import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
Jonathan Hartf5315fb2013-04-05 11:41:56 -070062
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070063public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080064
65 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066
67 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070068 protected volatile IFloodlightProviderService floodlightProvider;
69 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070070 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 protected OFMessageDamper messageDamper;
73
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070074 //
75 // TODO: Values copied from elsewhere (class LearningSwitch).
76 // The local copy should go away!
77 //
78 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
79 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
80 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
81 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
82 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080083
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000084 // Flow Entry ID generation state
85 private static Random randomGenerator = new Random();
86 private static int nextFlowEntryIdPrefix = 0;
87 private static int nextFlowEntryIdSuffix = 0;
88 private static long nextFlowEntryId = 0;
89
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070090 private static long measurementFlowId = 100000;
91 private static String measurementFlowIdStr = "0x186a0"; // 100000
92 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070093
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080094 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080095 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
96
97 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070098 private ScheduledExecutorService mapReaderScheduler;
99 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700100
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700101 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700103 try {
104 runImpl();
105 } catch (Exception e) {
106 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
107 conn.endTx(Transaction.ROLLBACK);
108 return;
109 }
110 }
111
112 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700113 long startTime = System.nanoTime();
114 int counterAllFlowEntries = 0;
115 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700116
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800117 if (floodlightProvider == null) {
118 log.debug("FloodlightProvider service not found!");
119 return;
120 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000121 Map<Long, IOFSwitch> mySwitches =
122 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700123 LinkedList<IFlowEntry> addFlowEntries =
124 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000125 LinkedList<IFlowEntry> deleteFlowEntries =
126 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700127
128 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700129 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700130 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700131 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700132 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 Iterable<IFlowEntry> allFlowEntries =
Pankaj Berded1c38592013-04-10 22:46:40 -0700134 conn.utils().getAllSwitchNotUpdatedFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700135 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700136 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000137
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000138 String dpidStr = flowEntryObj.getSwitchDpid();
139 if (dpidStr == null)
140 continue;
141 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800142 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000143 if (mySwitch == null)
144 continue; // Ignore the entry: not my switch
145
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700146 IFlowPath flowObj =
147 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
148 if (flowObj == null)
149 continue; // Should NOT happen
150 if (flowObj.getFlowId() == null)
151 continue; // Invalid entry
152
153 //
154 // NOTE: For now we process the DELETE before the ADD
155 // to cover the more common scenario.
156 // TODO: This is error prone and needs to be fixed!
157 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000158 String userState = flowEntryObj.getUserState();
159 if (userState == null)
160 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700161 if (userState.equals("FE_USER_DELETE")) {
162 // An entry that needs to be deleted.
163 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700164 installFlowEntry(mySwitch, flowObj, flowEntryObj);
165 } else {
166 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700167 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700168 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700170 // TODO: Commented-out for now
171 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700172 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700173 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700174 processed_measurement_flow = true;
175 }
176 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700177 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700178 }
179
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700180 //
181 // Process the Flow Entries that need to be added
182 //
183 for (IFlowEntry flowEntryObj : addFlowEntries) {
184 IFlowPath flowObj =
185 conn.utils().getFlowPathByFlowEntry(conn,
186 flowEntryObj);
187 if (flowObj == null)
188 continue; // Should NOT happen
189 if (flowObj.getFlowId() == null)
190 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700191
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700192 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700193 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000194 if (mySwitch == null)
195 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700196 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800197 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000198
199 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000200 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700201 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000202 //
203 // TODO: We should use the OpenFlow Barrier mechanism
204 // to check for errors, and delete the Flow Entries after the
205 // Barrier message is received.
206 //
207 while (! deleteFlowEntries.isEmpty()) {
208 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
209 IFlowPath flowObj =
210 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
211 if (flowObj == null) {
212 log.debug("Did not find FlowPath to be deleted");
213 continue;
214 }
215 flowObj.removeFlowEntry(flowEntryObj);
216 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000217 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700218
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700219 conn.endTx(Transaction.COMMIT);
220
221 if (processed_measurement_flow) {
222 long estimatedTime =
223 System.nanoTime() - modifiedMeasurementFlowTime;
224 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
225 (double)estimatedTime / 1000000000 + " sec";
226 log.debug(logMsg);
227 }
228
229 long estimatedTime = System.nanoTime() - startTime;
230 double rate = 0.0;
231 if (estimatedTime > 0)
232 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
233 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
234 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
235 counterMyNotUpdatedFlowEntries + " in " +
236 (double)estimatedTime / 1000000000 + " sec: " +
237 rate + " paths/s";
238 log.debug(logMsg);
239 }
240 };
241
242 final Runnable shortestPathReconcile = new Runnable() {
243 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700244 try {
245 runImpl();
246 } catch (Exception e) {
247 log.debug("Exception processing All Flows from the Network MAP: ", e);
248 conn.endTx(Transaction.ROLLBACK);
249 return;
250 }
251 }
252
253 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700254 long startTime = System.nanoTime();
255 int counterAllFlowPaths = 0;
256 int counterMyFlowPaths = 0;
257
258 if (floodlightProvider == null) {
259 log.debug("FloodlightProvider service not found!");
260 return;
261 }
262 Map<Long, IOFSwitch> mySwitches =
263 floodlightProvider.getSwitches();
264 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
265
266 boolean processed_measurement_flow = false;
267
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700268 //
269 // Fetch and recompute the Shortest Path for those
270 // Flow Paths this controller is responsible for.
271 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700272 topoRouteService.prepareShortestPathTopo();
273 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700274 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700275 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700276 if (flowPathObj == null)
277 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700278
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700279 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000280 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700281 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700282 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700283 //
284 // Use the source DPID as a heuristic to decide
285 // which controller is responsible for maintaining the
286 // shortest path.
287 // NOTE: This heuristic is error-prone: if the switch
288 // goes away and no controller is responsible for that
289 // switch, then the original Flow Path is not cleaned-up
290 //
291 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
292 if (mySwitch == null)
293 continue; // Ignore: not my responsibility
294
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700295 // Test the Data Path Summary string
296 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
297 if (dataPathSummaryStr == null)
298 continue; // Could be invalid entry?
299 if (dataPathSummaryStr.isEmpty())
300 continue; // No need to maintain this flow
301
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000302 //
303 // Test whether we need to complete the Flow cleanup,
304 // if the Flow has been deleted by the user.
305 //
306 String flowUserState = flowPathObj.getUserState();
307 if ((flowUserState != null)
308 && flowUserState.equals("FE_USER_DELETE")) {
309 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
310 boolean empty = true; // TODO: an ugly hack
311 for (IFlowEntry flowEntryObj : flowEntries) {
312 empty = false;
313 break;
314 }
315 if (empty)
316 deleteFlows.add(flowPathObj);
317 }
318
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000319 // Fetch the fields needed to recompute the shortest path
320 Short srcPortShort = flowPathObj.getSrcPort();
321 String dstDpidStr = flowPathObj.getDstSwitch();
322 Short dstPortShort = flowPathObj.getDstPort();
323 if ((srcPortShort == null) ||
324 (dstDpidStr == null) ||
325 (dstPortShort == null)) {
326 continue;
327 }
328
329 Port srcPort = new Port(srcPortShort);
330 Dpid dstDpid = new Dpid(dstDpidStr);
331 Port dstPort = new Port(dstPortShort);
332 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
333 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
334
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700335 counterMyFlowPaths++;
336
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700337 //
338 // NOTE: Using here the regular getShortestPath() method
339 // won't work here, because that method calls internally
340 // "conn.endTx(Transaction.COMMIT)", and that will
341 // invalidate all handlers to the Titan database.
342 // If we want to experiment with calling here
343 // getShortestPath(), we need to refactor that code
344 // to avoid closing the transaction.
345 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700346 DataPath dataPath =
347 topoRouteService.getTopoShortestPath(srcSwitchPort,
348 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000349 if (dataPath == null) {
350 // We need the DataPath to compare the paths
351 dataPath = new DataPath();
352 dataPath.setSrcPort(srcSwitchPort);
353 dataPath.setDstPort(dstSwitchPort);
354 }
355
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700356 String newDataPathSummaryStr = dataPath.dataPathSummary();
357 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
358 continue; // Nothing changed
359
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700360 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700361 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000362
363 //
364 // Delete all leftover Flows marked for deletion from the
365 // Network MAP.
366 //
367 while (! deleteFlows.isEmpty()) {
368 IFlowPath flowPathObj = deleteFlows.poll();
369 conn.utils().removeFlowPath(conn, flowPathObj);
370 }
371
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700372 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700373
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800374 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700375
376 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700377 long estimatedTime =
378 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700379 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
380 (double)estimatedTime / 1000000000 + " sec";
381 log.debug(logMsg);
382 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700383
384 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700385 double rate = 0.0;
386 if (estimatedTime > 0)
387 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700388 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700389 counterAllFlowPaths + " MyFlowPaths: " +
390 counterMyFlowPaths + " in " +
391 (double)estimatedTime / 1000000000 + " sec: " +
392 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700393 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800394 }
395 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700396
Jonathan Hart50a94982013-04-10 14:49:51 -0700397 //final ScheduledFuture<?> mapReaderHandle =
398 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800399
Jonathan Hart50a94982013-04-10 14:49:51 -0700400 //final ScheduledFuture<?> shortestPathReconcileHandle =
401 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700402
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800403 @Override
404 public void init(String conf) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700405 conn = GraphDBConnection.getInstance(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800406 }
407
408 public void finalize() {
409 close();
410 }
411
412 @Override
413 public void close() {
414 conn.close();
415 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800416
417 @Override
418 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
419 Collection<Class<? extends IFloodlightService>> l =
420 new ArrayList<Class<? extends IFloodlightService>>();
421 l.add(IFlowService.class);
422 return l;
423 }
424
425 @Override
426 public Map<Class<? extends IFloodlightService>, IFloodlightService>
427 getServiceImpls() {
428 Map<Class<? extends IFloodlightService>,
429 IFloodlightService> m =
430 new HashMap<Class<? extends IFloodlightService>,
431 IFloodlightService>();
432 m.put(IFlowService.class, this);
433 return m;
434 }
435
436 @Override
437 public Collection<Class<? extends IFloodlightService>>
438 getModuleDependencies() {
439 Collection<Class<? extends IFloodlightService>> l =
440 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800441 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700442 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800443 l.add(IRestApiService.class);
444 return l;
445 }
446
447 @Override
448 public void init(FloodlightModuleContext context)
449 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700450 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800451 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700452 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800453 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800454 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
455 EnumSet.of(OFType.FLOW_MOD),
456 OFMESSAGE_DAMPER_TIMEOUT);
457 // TODO: An ugly hack!
458 String conf = "/tmp/cassandra.titan";
459 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700460
461 mapReaderScheduler = Executors.newScheduledThreadPool(1);
462 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 }
464
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000465 private long getNextFlowEntryId() {
466 //
467 // Generate the next Flow Entry ID.
468 // NOTE: For now, the higher 32 bits are random, and
469 // the lower 32 bits are sequential.
470 // In the future, we need a better allocation mechanism.
471 //
472 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
473 nextFlowEntryIdPrefix = randomGenerator.nextInt();
474 nextFlowEntryIdSuffix = 0;
475 } else {
476 nextFlowEntryIdSuffix++;
477 }
478 long result = (long)nextFlowEntryIdPrefix << 32;
479 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
480 return result;
481 }
482
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800483 @Override
484 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700485 restApi.addRestletRoutable(new FlowWebRoutable());
486
487 // Initialize the Flow Entry ID generator
488 nextFlowEntryIdPrefix = randomGenerator.nextInt();
489
490 mapReaderScheduler.scheduleAtFixedRate(
491 mapReader, 3, 3, TimeUnit.SECONDS);
492 shortestPathReconcileScheduler.scheduleAtFixedRate(
493 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800494 }
495
496 /**
497 * Add a flow.
498 *
499 * Internally, ONOS will automatically register the installer for
500 * receiving Flow Path Notifications for that path.
501 *
502 * @param flowPath the Flow Path to install.
503 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700504 * @param dataPathSummaryStr the data path summary string if the added
505 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800506 * @return true on success, otherwise false.
507 */
508 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700509 public boolean addFlow(FlowPath flowPath, FlowId flowId,
510 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700511 /*
512 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700513 if (flowPath.flowId().value() == measurementFlowId) {
514 modifiedMeasurementFlowTime = System.nanoTime();
515 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700516 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800517
518 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000519 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800520 try {
521 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
522 != null) {
523 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
524 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000525 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800526 } else {
527 flowObj = conn.utils().newFlowPath(conn);
528 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
529 flowPath.flowId().toString());
530 }
531 } catch (Exception e) {
532 // TODO: handle exceptions
533 conn.endTx(Transaction.ROLLBACK);
534 log.error(":addFlow FlowId:{} failed",
535 flowPath.flowId().toString());
536 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700537 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000538 log.error(":addFlow FlowId:{} failed: Flow object not created",
539 flowPath.flowId().toString());
540 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800541 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700542 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800543
544 //
545 // Set the Flow key:
546 // - flowId
547 //
548 flowObj.setFlowId(flowPath.flowId().toString());
549 flowObj.setType("flow");
550
551 //
552 // Set the Flow attributes:
553 // - flowPath.installerId()
554 // - flowPath.dataPath().srcPort()
555 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700556 // - flowPath.matchEthernetFrameType()
557 // - flowPath.matchSrcIPv4Net()
558 // - flowPath.matchDstIPv4Net()
559 // - flowPath.matchSrcMac()
560 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800561 //
562 flowObj.setInstallerId(flowPath.installerId().toString());
563 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
564 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
565 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
566 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700567 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
568 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
569 }
570 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
571 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
572 }
573 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
574 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
575 }
576 if (flowPath.flowEntryMatch().matchSrcMac()) {
577 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
578 }
579 if (flowPath.flowEntryMatch().matchDstMac()) {
580 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
581 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800582
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700583 if (dataPathSummaryStr != null) {
584 flowObj.setDataPathSummary(dataPathSummaryStr);
585 } else {
586 flowObj.setDataPathSummary("");
587 }
588
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000589 if (found)
590 flowObj.setUserState("FE_USER_MODIFY");
591 else
592 flowObj.setUserState("FE_USER_ADD");
593
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800594 // Flow edges:
595 // HeadFE
596
597
598 //
599 // Flow Entries:
600 // flowPath.dataPath().flowEntries()
601 //
602 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700603 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000604 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800605 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700606 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800607 }
608 conn.endTx(Transaction.COMMIT);
609
610 //
611 // TODO: We need a proper Flow ID allocation mechanism.
612 //
613 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700614
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800615 return true;
616 }
617
618 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700619 * Add a flow entry to the Network MAP.
620 *
621 * @param flowObj the corresponding Flow Path object for the Flow Entry.
622 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700623 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700624 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700625 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700626 // Flow edges
627 // HeadFE (TODO)
628
629 //
630 // Assign the FlowEntry ID.
631 //
632 if ((flowEntry.flowEntryId() == null) ||
633 (flowEntry.flowEntryId().value() == 0)) {
634 long id = getNextFlowEntryId();
635 flowEntry.setFlowEntryId(new FlowEntryId(id));
636 }
637
638 IFlowEntry flowEntryObj = null;
639 boolean found = false;
640 try {
641 if ((flowEntryObj =
642 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
643 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
644 flowEntry.flowEntryId().toString());
645 found = true;
646 } else {
647 flowEntryObj = conn.utils().newFlowEntry(conn);
648 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
649 flowEntry.flowEntryId().toString());
650 }
651 } catch (Exception e) {
652 log.error(":addFlow FlowEntryId:{} failed",
653 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700654 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700655 }
656 if (flowEntryObj == null) {
657 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
658 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700659 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700660 }
661
662 //
663 // Set the Flow Entry key:
664 // - flowEntry.flowEntryId()
665 //
666 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
667 flowEntryObj.setType("flow_entry");
668
669 //
670 // Set the Flow Entry Edges and attributes:
671 // - Switch edge
672 // - InPort edge
673 // - OutPort edge
674 //
675 // - flowEntry.flowEntryMatch()
676 // - flowEntry.flowEntryActions()
677 // - flowEntry.dpid()
678 // - flowEntry.flowEntryUserState()
679 // - flowEntry.flowEntrySwitchState()
680 // - flowEntry.flowEntryErrorState()
681 // - flowEntry.matchInPort()
682 // - flowEntry.matchEthernetFrameType()
683 // - flowEntry.matchSrcIPv4Net()
684 // - flowEntry.matchDstIPv4Net()
685 // - flowEntry.matchSrcMac()
686 // - flowEntry.matchDstMac()
687 // - flowEntry.actionOutput()
688 //
689 ISwitchObject sw =
690 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
691 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
692 flowEntryObj.setSwitch(sw);
693 if (flowEntry.flowEntryMatch().matchInPort()) {
694 IPortObject inport =
695 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
696 flowEntry.flowEntryMatch().inPort().value());
697 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
698 flowEntryObj.setInPort(inport);
699 }
700 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
701 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
702 }
703 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
704 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
705 }
706 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
707 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
708 }
709 if (flowEntry.flowEntryMatch().matchSrcMac()) {
710 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
711 }
712 if (flowEntry.flowEntryMatch().matchDstMac()) {
713 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
714 }
715
716 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
717 if (fa.actionOutput() != null) {
718 IPortObject outport =
719 conn.utils().searchPort(conn,
720 flowEntry.dpid().toString(),
721 fa.actionOutput().port().value());
722 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
723 flowEntryObj.setOutPort(outport);
724 }
725 }
726 // TODO: Hacks with hard-coded state names!
727 if (found)
728 flowEntryObj.setUserState("FE_USER_MODIFY");
729 else
730 flowEntryObj.setUserState("FE_USER_ADD");
731 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
732 //
733 // TODO: Take care of the FlowEntryErrorState.
734 //
735
736 // Flow Entries edges:
737 // Flow
738 // NextFE (TODO)
739 if (! found) {
740 flowObj.addFlowEntry(flowEntryObj);
741 flowEntryObj.setFlow(flowObj);
742 }
743
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700744 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700745 }
746
747 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800748 * Delete a previously added flow.
749 *
750 * @param flowId the Flow ID of the flow to delete.
751 * @return true on success, otherwise false.
752 */
753 @Override
754 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700755 /*
756 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700757 if (flowId.value() == measurementFlowId) {
758 modifiedMeasurementFlowTime = System.nanoTime();
759 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700760 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700761
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800762 IFlowPath flowObj = null;
763 //
764 // We just mark the entries for deletion,
765 // and let the switches remove each individual entry after
766 // it has been removed from the switches.
767 //
768 try {
769 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
770 != null) {
771 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
772 flowId.toString());
773 } else {
774 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
775 flowId.toString());
776 }
777 } catch (Exception e) {
778 // TODO: handle exceptions
779 conn.endTx(Transaction.ROLLBACK);
780 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
781 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700782 if (flowObj == null) {
783 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800784 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700785 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800786
787 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000788 // Find and mark for deletion all Flow Entries,
789 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800790 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000791 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800792 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
793 boolean empty = true; // TODO: an ugly hack
794 for (IFlowEntry flowEntryObj : flowEntries) {
795 empty = false;
796 // flowObj.removeFlowEntry(flowEntryObj);
797 // conn.utils().removeFlowEntry(conn, flowEntryObj);
798 flowEntryObj.setUserState("FE_USER_DELETE");
799 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
800 }
801 // Remove from the database empty flows
802 if (empty)
803 conn.utils().removeFlowPath(conn, flowObj);
804 conn.endTx(Transaction.COMMIT);
805
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800806 return true;
807 }
808
809 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700810 * Clear the state for a previously added flow.
811 *
812 * @param flowId the Flow ID of the flow to clear.
813 * @return true on success, otherwise false.
814 */
815 @Override
816 public boolean clearFlow(FlowId flowId) {
817 IFlowPath flowObj = null;
818 try {
819 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
820 != null) {
821 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
822 flowId.toString());
823 } else {
824 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
825 flowId.toString());
826 }
827 } catch (Exception e) {
828 // TODO: handle exceptions
829 conn.endTx(Transaction.ROLLBACK);
830 log.error(":clearFlow FlowId:{} failed", flowId.toString());
831 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700832 if (flowObj == null) {
833 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700834 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700835 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700836
837 //
838 // Remove all Flow Entries
839 //
840 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
841 for (IFlowEntry flowEntryObj : flowEntries) {
842 flowObj.removeFlowEntry(flowEntryObj);
843 conn.utils().removeFlowEntry(conn, flowEntryObj);
844 }
845 // Remove the Flow itself
846 conn.utils().removeFlowPath(conn, flowObj);
847 conn.endTx(Transaction.COMMIT);
848
849 return true;
850 }
851
852 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800853 * Get a previously added flow.
854 *
855 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800856 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800857 */
858 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800859 public FlowPath getFlow(FlowId flowId) {
860 IFlowPath flowObj = null;
861 try {
862 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
863 != null) {
864 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
865 flowId.toString());
866 } else {
867 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
868 flowId.toString());
869 }
870 } catch (Exception e) {
871 // TODO: handle exceptions
872 conn.endTx(Transaction.ROLLBACK);
873 log.error(":getFlow FlowId:{} failed", flowId.toString());
874 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700875 if (flowObj == null) {
876 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800877 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700878 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800879
880 //
881 // Extract the Flow state
882 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800883 FlowPath flowPath = extractFlowPath(flowObj);
884 conn.endTx(Transaction.COMMIT);
885
886 return flowPath;
887 }
888
889 /**
890 * Get all previously added flows by a specific installer for a given
891 * data path endpoints.
892 *
893 * @param installerId the Caller ID of the installer of the flow to get.
894 * @param dataPathEndpoints the data path endpoints of the flow to get.
895 * @return the Flow Paths if found, otherwise null.
896 */
897 @Override
898 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
899 DataPathEndpoints dataPathEndpoints) {
900 //
901 // TODO: The implementation below is not optimal:
902 // We fetch all flows, and then return only the subset that match
903 // the query conditions.
904 // We should use the appropriate Titan/Gremlin query to filter-out
905 // the flows as appropriate.
906 //
907 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700908 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800909
910 if (allFlows == null) {
911 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700912 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800913 }
914
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800915 for (FlowPath flow : allFlows) {
916 //
917 // TODO: String-based comparison is sub-optimal.
918 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800919 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800920 //
921 if (! flow.installerId().toString().equals(installerId.toString()))
922 continue;
923 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
924 continue;
925 }
926 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
927 continue;
928 }
929 flowPaths.add(flow);
930 }
931
932 if (flowPaths.isEmpty()) {
933 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800934 } else {
935 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
936 }
937
938 return flowPaths;
939 }
940
941 /**
942 * Get all installed flows by all installers for given data path endpoints.
943 *
944 * @param dataPathEndpoints the data path endpoints of the flows to get.
945 * @return the Flow Paths if found, otherwise null.
946 */
947 @Override
948 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
949 //
950 // TODO: The implementation below is not optimal:
951 // We fetch all flows, and then return only the subset that match
952 // the query conditions.
953 // We should use the appropriate Titan/Gremlin query to filter-out
954 // the flows as appropriate.
955 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700956 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
957 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800958
959 if (allFlows == null) {
960 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700961 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800962 }
963
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800964 for (FlowPath flow : allFlows) {
965 //
966 // TODO: String-based comparison is sub-optimal.
967 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800968 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800969 //
970 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
971 continue;
972 }
973 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
974 continue;
975 }
976 flowPaths.add(flow);
977 }
978
979 if (flowPaths.isEmpty()) {
980 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800981 } else {
982 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
983 }
984
985 return flowPaths;
986 }
987
988 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700989 * Get summary of all installed flows by all installers in a given range
990 *
991 * @param flowId the data path endpoints of the flows to get.
992 * @param maxFlows: the maximum number of flows to be returned
993 * @return the Flow Paths if found, otherwise null.
994 */
995 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700996 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700997
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700998 // TODO: The implementation below is not optimal:
999 // We fetch all flows, and then return only the subset that match
1000 // the query conditions.
1001 // We should use the appropriate Titan/Gremlin query to filter-out
1002 // the flows as appropriate.
1003 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001004 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001005
Jonathan Hart01f2d272013-04-04 20:03:46 -07001006 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1007
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001008 Collections.sort(flowPathsWithoutFlowEntries,
1009 new Comparator<IFlowPath>(){
1010 @Override
1011 public int compare(IFlowPath first, IFlowPath second) {
1012 // TODO Auto-generated method stub
1013 long result = new FlowId(first.getFlowId()).value()
1014 - new FlowId(second.getFlowId()).value();
1015 if (result > 0) return 1;
1016 else if (result < 0) return -1;
1017 else return 0;
1018 }
1019 }
1020 );
1021
Jonathan Hart01f2d272013-04-04 20:03:46 -07001022 return flowPathsWithoutFlowEntries;
1023
1024 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001025 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001026
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001027 if (allFlows == null) {
1028 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001029 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001030 }
1031
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001032 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001033
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001034 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001035 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001036
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001037 // start from desired flowId
1038 if (flow.flowId().value() < flowId.value()) {
1039 continue;
1040 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001041
1042 // Summarize by making null flow entry fields that are not relevant to report
1043 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1044 flowEntry.setFlowEntryActions(null);
1045 flowEntry.setFlowEntryMatch(null);
1046 }
1047
1048 flowPaths.add(flow);
1049 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1050 break;
1051 }
1052 }
1053
1054 if (flowPaths.isEmpty()) {
1055 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001056 } else {
1057 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1058 }
1059
1060 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001061 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001062 }
1063
1064 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001065 * Get all installed flows by all installers.
1066 *
1067 * @return the Flow Paths if found, otherwise null.
1068 */
1069 @Override
1070 public ArrayList<FlowPath> getAllFlows() {
1071 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001072 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001073
1074 try {
1075 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1076 log.debug("Get all FlowPaths: found FlowPaths");
1077 } else {
1078 log.debug("Get all FlowPaths: no FlowPaths found");
1079 }
1080 } catch (Exception e) {
1081 // TODO: handle exceptions
1082 conn.endTx(Transaction.ROLLBACK);
1083 log.error(":getAllFlowPaths failed");
1084 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001085 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1086 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001087 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001088 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001089
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001090 for (IFlowPath flowObj : flowPathsObj) {
1091 //
1092 // Extract the Flow state
1093 //
1094 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001095 if (flowPath != null)
1096 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001097 }
1098
1099 conn.endTx(Transaction.COMMIT);
1100
1101 return flowPaths;
1102 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001103
1104 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1105 Iterable<IFlowPath> flowPathsObj = null;
1106 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1107 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1108
1109 try {
1110 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1111 log.debug("Get all FlowPaths: found FlowPaths");
1112 } else {
1113 log.debug("Get all FlowPaths: no FlowPaths found");
1114 }
1115 } catch (Exception e) {
1116 // TODO: handle exceptions
1117 conn.endTx(Transaction.ROLLBACK);
1118 log.error(":getAllFlowPaths failed");
1119 }
1120 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1121 return new ArrayList<IFlowPath>(); // No Flows found
1122 }
1123
1124 for (IFlowPath flowObj : flowPathsObj){
1125 flowPathsObjArray.add(flowObj);
1126 }
1127 /*
1128 for (IFlowPath flowObj : flowPathsObj) {
1129 //
1130 // Extract the Flow state
1131 //
1132 FlowPath flowPath = extractFlowPath(flowObj);
1133 if (flowPath != null)
1134 flowPaths.add(flowPath);
1135 }
1136 */
1137
1138 //conn.endTx(Transaction.COMMIT);
1139
1140 return flowPathsObjArray;
1141 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001142
1143 /**
1144 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1145 *
1146 * @param flowObj the object to extract the Flow Path State from.
1147 * @return the extracted Flow Path State.
1148 */
1149 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001150 //
1151 // Extract the Flow state
1152 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001153 String flowIdStr = flowObj.getFlowId();
1154 String installerIdStr = flowObj.getInstallerId();
1155 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001156 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001157 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001158 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001159
1160 if ((flowIdStr == null) ||
1161 (installerIdStr == null) ||
1162 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001163 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001164 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001165 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001166 // TODO: A work-around, becauuse of some bogus database objects
1167 return null;
1168 }
1169
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001170 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001171 flowPath.setFlowId(new FlowId(flowIdStr));
1172 flowPath.setInstallerId(new CallerId(installerIdStr));
1173 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001174 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001175 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001176 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001177 //
1178 // Extract the match conditions common for all Flow Entries
1179 //
1180 {
1181 FlowEntryMatch match = new FlowEntryMatch();
1182 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1183 if (matchEthernetFrameType != null)
1184 match.enableEthernetFrameType(matchEthernetFrameType);
1185 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1186 if (matchSrcIPv4Net != null)
1187 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1188 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1189 if (matchDstIPv4Net != null)
1190 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1191 String matchSrcMac = flowObj.getMatchSrcMac();
1192 if (matchSrcMac != null)
1193 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1194 String matchDstMac = flowObj.getMatchDstMac();
1195 if (matchDstMac != null)
1196 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1197 flowPath.setFlowEntryMatch(match);
1198 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001199
1200 //
1201 // Extract all Flow Entries
1202 //
1203 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1204 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001205 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1206 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001207 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001208 flowPath.dataPath().flowEntries().add(flowEntry);
1209 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001210
1211 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001212 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001213
1214 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001215 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1216 *
1217 * @param flowEntryObj the object to extract the Flow Entry State from.
1218 * @return the extracted Flow Entry State.
1219 */
1220 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1221 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1222 String switchDpidStr = flowEntryObj.getSwitchDpid();
1223 String userState = flowEntryObj.getUserState();
1224 String switchState = flowEntryObj.getSwitchState();
1225
1226 if ((flowEntryIdStr == null) ||
1227 (switchDpidStr == null) ||
1228 (userState == null) ||
1229 (switchState == null)) {
1230 // TODO: A work-around, becauuse of some bogus database objects
1231 return null;
1232 }
1233
1234 FlowEntry flowEntry = new FlowEntry();
1235 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1236 flowEntry.setDpid(new Dpid(switchDpidStr));
1237
1238 //
1239 // Extract the match conditions
1240 //
1241 FlowEntryMatch match = new FlowEntryMatch();
1242 Short matchInPort = flowEntryObj.getMatchInPort();
1243 if (matchInPort != null)
1244 match.enableInPort(new Port(matchInPort));
1245 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1246 if (matchEthernetFrameType != null)
1247 match.enableEthernetFrameType(matchEthernetFrameType);
1248 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1249 if (matchSrcIPv4Net != null)
1250 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1251 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1252 if (matchDstIPv4Net != null)
1253 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1254 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1255 if (matchSrcMac != null)
1256 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1257 String matchDstMac = flowEntryObj.getMatchDstMac();
1258 if (matchDstMac != null)
1259 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1260 flowEntry.setFlowEntryMatch(match);
1261
1262 //
1263 // Extract the actions
1264 //
1265 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1266 Short actionOutputPort = flowEntryObj.getActionOutput();
1267 if (actionOutputPort != null) {
1268 FlowEntryAction action = new FlowEntryAction();
1269 action.setActionOutput(new Port(actionOutputPort));
1270 actions.add(action);
1271 }
1272 flowEntry.setFlowEntryActions(actions);
1273 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1274 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1275 //
1276 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1277 // and FlowEntryErrorState.
1278 //
1279 return flowEntry;
1280 }
1281
1282 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001283 * Add and maintain a shortest-path flow.
1284 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001285 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001286 *
1287 * @param flowPath the Flow Path with the endpoints and the match
1288 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001289 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001290 */
1291 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001292 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001293 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001294 // Don't do the shortest path computation here.
1295 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001296 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001297
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001298 // We need the DataPath to populate the Network MAP
1299 DataPath dataPath = new DataPath();
1300 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1301 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001302
1303 //
1304 // Prepare the computed Flow Path
1305 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001306 FlowPath computedFlowPath = new FlowPath();
1307 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1308 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1309 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001310 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001311
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001312 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001313 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001314 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001315 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001316
1317 // TODO: Mark the flow for maintenance purpose
1318
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001319 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001320 }
1321
1322 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001323 * Reconcile a flow.
1324 *
1325 * @param flowObj the flow that needs to be reconciliated.
1326 * @param newDataPath the new data path to use.
1327 * @return true on success, otherwise false.
1328 */
1329 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1330 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1331
1332 //
1333 // Set the incoming port matching and the outgoing port output
1334 // actions for each flow entry.
1335 //
1336 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1337 // Set the incoming port matching
1338 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1339 flowEntry.setFlowEntryMatch(flowEntryMatch);
1340 flowEntryMatch.enableInPort(flowEntry.inPort());
1341
1342 // Set the outgoing port output action
1343 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1344 if (flowEntryActions == null) {
1345 flowEntryActions = new ArrayList<FlowEntryAction>();
1346 flowEntry.setFlowEntryActions(flowEntryActions);
1347 }
1348 FlowEntryAction flowEntryAction = new FlowEntryAction();
1349 flowEntryAction.setActionOutput(flowEntry.outPort());
1350 flowEntryActions.add(flowEntryAction);
1351 }
1352
1353 //
1354 // Remove the old Flow Entries, and add the new Flow Entries
1355 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001356 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1357 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1358 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001359 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001360 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001361 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001362 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001363 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001364 }
1365
1366 //
1367 // Set the Data Path Summary
1368 //
1369 String dataPathSummaryStr = newDataPath.dataPathSummary();
1370 flowObj.setDataPathSummary(dataPathSummaryStr);
1371
1372 return true;
1373 }
1374
1375 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001376 * Reconcile all flows in a set.
1377 *
1378 * @param flowObjSet the set of flows that need to be reconciliated.
1379 */
1380 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1381 if (! flowObjSet.iterator().hasNext())
1382 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001383 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001384 }
1385
1386 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001387 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001388 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001389 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001390 * @param flowObj the flow path object for the flow entry to install.
1391 * @param flowEntryObj the flow entry object to install.
1392 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001393 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001394 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1395 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001396 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1397 if (flowEntryIdStr == null)
1398 return false;
1399 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001400 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001401 if (userState == null)
1402 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001403
1404 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001405 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001406 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001407 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1408 .getMessage(OFType.FLOW_MOD);
1409 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001410
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001411 short flowModCommand = OFFlowMod.OFPFC_ADD;
1412 if (userState.equals("FE_USER_ADD")) {
1413 flowModCommand = OFFlowMod.OFPFC_ADD;
1414 } else if (userState.equals("FE_USER_MODIFY")) {
1415 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1416 } else if (userState.equals("FE_USER_DELETE")) {
1417 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1418 } else {
1419 // Unknown user state. Ignore the entry
1420 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1421 flowEntryId.toString(), userState);
1422 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423 }
1424
1425 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001426 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001427 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001428 // NOTE: The Flow matching conditions common for all Flow Entries are
1429 // used ONLY if a Flow Entry does NOT have the corresponding matching
1430 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001431 //
1432 OFMatch match = new OFMatch();
1433 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001434
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001435 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001436 Short matchInPort = flowEntryObj.getMatchInPort();
1437 if (matchInPort != null) {
1438 match.setInputPort(matchInPort);
1439 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1440 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001441
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001442 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001443 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1444 if (matchEthernetFrameType == null)
1445 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1446 if (matchEthernetFrameType != null) {
1447 match.setDataLayerType(matchEthernetFrameType);
1448 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1449 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001450
1451 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001452 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1453 if (matchSrcIPv4Net == null)
1454 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1455 if (matchSrcIPv4Net != null) {
1456 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1457 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001458
1459 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001460 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1461 if (matchDstIPv4Net == null)
1462 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1463 if (matchDstIPv4Net != null) {
1464 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1465 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001466
1467 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001468 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1469 if (matchSrcMac == null)
1470 matchSrcMac = flowObj.getMatchSrcMac();
1471 if (matchSrcMac != null) {
1472 match.setDataLayerSource(matchSrcMac);
1473 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1474 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001475
1476 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001477 String matchDstMac = flowEntryObj.getMatchDstMac();
1478 if (matchDstMac == null)
1479 matchDstMac = flowObj.getMatchDstMac();
1480 if (matchDstMac != null) {
1481 match.setDataLayerDestination(matchDstMac);
1482 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1483 }
1484
1485 //
1486 // Fetch the actions
1487 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001488 // TODO: For now we support only the "OUTPUT" actions.
1489 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001490 List<OFAction> actions = new ArrayList<OFAction>();
1491 Short actionOutputPort = flowEntryObj.getActionOutput();
1492 if (actionOutputPort != null) {
1493 OFActionOutput action = new OFActionOutput();
1494 // XXX: The max length is hard-coded for now
1495 action.setMaxLength((short)0xffff);
1496 action.setPort(actionOutputPort);
1497 actions.add(action);
1498 }
1499
1500 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1501 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1502 .setPriority(PRIORITY_DEFAULT)
1503 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1504 .setCookie(cookie)
1505 .setCommand(flowModCommand)
1506 .setMatch(match)
1507 .setActions(actions)
1508 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1509 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1510 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1511 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1512 if (actionOutputPort != null)
1513 fm.setOutPort(actionOutputPort);
1514 }
1515
1516 //
1517 // TODO: Set the following flag
1518 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1519 // See method ForwardingBase::pushRoute()
1520 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001521
1522 //
1523 // Write the message to the switch
1524 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001525 log.debug("MEASUREMENT: Installing flow entry " + userState +
1526 " into switch DPID: " +
1527 mySwitch.getStringId() +
1528 " flowEntryId: " + flowEntryId.toString() +
1529 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1530 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1531 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001532 try {
1533 messageDamper.write(mySwitch, fm, null);
1534 mySwitch.flush();
1535 //
1536 // TODO: We should use the OpenFlow Barrier mechanism
1537 // to check for errors, and update the SwitchState
1538 // for a flow entry after the Barrier message is
1539 // is received.
1540 //
1541 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1542 } catch (IOException e) {
1543 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001544 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001545 }
1546
1547 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001548 }
1549
1550 /**
1551 * Install a Flow Entry on a switch.
1552 *
1553 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001554 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001555 * @param flowEntry the flow entry to install.
1556 * @return true on success, otherwise false.
1557 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001558 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1559 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001560 //
1561 // Create the OpenFlow Flow Modification Entry to push
1562 //
1563 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1564 .getMessage(OFType.FLOW_MOD);
1565 long cookie = flowEntry.flowEntryId().value();
1566
1567 short flowModCommand = OFFlowMod.OFPFC_ADD;
1568 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1569 flowModCommand = OFFlowMod.OFPFC_ADD;
1570 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1571 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1572 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1573 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1574 } else {
1575 // Unknown user state. Ignore the entry
1576 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1577 flowEntry.flowEntryId().toString(),
1578 flowEntry.flowEntryUserState());
1579 return false;
1580 }
1581
1582 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001583 // Fetch the match conditions.
1584 //
1585 // NOTE: The Flow matching conditions common for all Flow Entries are
1586 // used ONLY if a Flow Entry does NOT have the corresponding matching
1587 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001588 //
1589 OFMatch match = new OFMatch();
1590 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001591 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1592 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1593
1594 // Match the Incoming Port
1595 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001596 if (matchInPort != null) {
1597 match.setInputPort(matchInPort.value());
1598 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1599 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001600
1601 // Match the Ethernet Frame Type
1602 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1603 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1604 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1605 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001606 if (matchEthernetFrameType != null) {
1607 match.setDataLayerType(matchEthernetFrameType);
1608 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1609 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001610
1611 // Match the Source IPv4 Network prefix
1612 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1613 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1614 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1615 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001616 if (matchSrcIPv4Net != null) {
1617 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1618 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001619
1620 // Natch the Destination IPv4 Network prefix
1621 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1622 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1623 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1624 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001625 if (matchDstIPv4Net != null) {
1626 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1627 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001628
1629 // Match the Source MAC address
1630 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1631 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1632 matchSrcMac = flowPathMatch.srcMac();
1633 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001634 if (matchSrcMac != null) {
1635 match.setDataLayerSource(matchSrcMac.toString());
1636 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1637 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001638
1639 // Match the Destination MAC address
1640 MACAddress matchDstMac = flowEntryMatch.dstMac();
1641 if ((matchDstMac == null) && (flowPathMatch != null)) {
1642 matchDstMac = flowPathMatch.dstMac();
1643 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001644 if (matchDstMac != null) {
1645 match.setDataLayerDestination(matchDstMac.toString());
1646 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1647 }
1648
1649 //
1650 // Fetch the actions
1651 //
1652 // TODO: For now we support only the "OUTPUT" actions.
1653 //
1654 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1655 List<OFAction> actions = new ArrayList<OFAction>();
1656 ArrayList<FlowEntryAction> flowEntryActions =
1657 flowEntry.flowEntryActions();
1658 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1659 FlowEntryAction.ActionOutput actionOutput =
1660 flowEntryAction.actionOutput();
1661 if (actionOutput != null) {
1662 short actionOutputPort = actionOutput.port().value();
1663 OFActionOutput action = new OFActionOutput();
1664 // XXX: The max length is hard-coded for now
1665 action.setMaxLength((short)0xffff);
1666 action.setPort(actionOutputPort);
1667 actions.add(action);
1668 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1669 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1670 fm.setOutPort(actionOutputPort);
1671 }
1672 }
1673 }
1674
1675 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1676 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1677 .setPriority(PRIORITY_DEFAULT)
1678 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1679 .setCookie(cookie)
1680 .setCommand(flowModCommand)
1681 .setMatch(match)
1682 .setActions(actions)
1683 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1684
1685 //
1686 // TODO: Set the following flag
1687 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1688 // See method ForwardingBase::pushRoute()
1689 //
1690
1691 //
1692 // Write the message to the switch
1693 //
1694 try {
1695 messageDamper.write(mySwitch, fm, null);
1696 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001697 //
1698 // TODO: We should use the OpenFlow Barrier mechanism
1699 // to check for errors, and update the SwitchState
1700 // for a flow entry after the Barrier message is
1701 // is received.
1702 //
1703 // TODO: The FlowEntry Object in Titan should be set
1704 // to FE_SWITCH_UPDATED.
1705 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001706 } catch (IOException e) {
1707 log.error("Failure writing flow mod from network map", e);
1708 return false;
1709 }
1710 return true;
1711 }
1712
1713 /**
1714 * Remove a Flow Entry from a switch.
1715 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001716 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001717 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001718 * @param flowEntry the flow entry to remove.
1719 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001720 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001721 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1722 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001723 //
1724 // The installFlowEntry() method implements both installation
1725 // and removal of flow entries.
1726 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001727 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001728 }
1729
1730 /**
1731 * Install a Flow Entry on a remote controller.
1732 *
1733 * TODO: We need it now: Jono
1734 * - For now it will make a REST call to the remote controller.
1735 * - Internally, it needs to know the name of the remote controller.
1736 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001737 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001738 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001739 * @return true on success, otherwise false.
1740 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001741 public boolean installRemoteFlowEntry(FlowPath flowPath,
1742 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001743 // TODO: We need it now: Jono
1744 // - For now it will make a REST call to the remote controller.
1745 // - Internally, it needs to know the name of the remote controller.
1746 return true;
1747 }
1748
1749 /**
1750 * Remove a flow entry on a remote controller.
1751 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001752 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001753 * @param flowEntry the flow entry to remove.
1754 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001755 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001756 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1757 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001758 //
1759 // The installRemoteFlowEntry() method implements both installation
1760 // and removal of flow entries.
1761 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001762 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001763 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001764}