blob: 307919ab67af99061203604a1a19bf62343027df [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 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700129 // Fetch all Flow Entries which need to be updated 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(
Pankaj Berde55f121a2013-04-23 15:42:54 -0700491 mapReader, 1, 1, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700492 shortestPathReconcileScheduler.scheduleAtFixedRate(
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700493 shortestPathReconcile, 100, 100, TimeUnit.MILLISECONDS);
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
Jonathan Harte6e91872013-04-13 11:10:32 -07001109 conn.endTx(Transaction.COMMIT);
1110
Jonathan Hart01f2d272013-04-04 20:03:46 -07001111 try {
1112 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1113 log.debug("Get all FlowPaths: found FlowPaths");
1114 } else {
1115 log.debug("Get all FlowPaths: no FlowPaths found");
1116 }
1117 } catch (Exception e) {
1118 // TODO: handle exceptions
1119 conn.endTx(Transaction.ROLLBACK);
1120 log.error(":getAllFlowPaths failed");
1121 }
1122 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1123 return new ArrayList<IFlowPath>(); // No Flows found
1124 }
1125
1126 for (IFlowPath flowObj : flowPathsObj){
1127 flowPathsObjArray.add(flowObj);
1128 }
1129 /*
1130 for (IFlowPath flowObj : flowPathsObj) {
1131 //
1132 // Extract the Flow state
1133 //
1134 FlowPath flowPath = extractFlowPath(flowObj);
1135 if (flowPath != null)
1136 flowPaths.add(flowPath);
1137 }
1138 */
1139
1140 //conn.endTx(Transaction.COMMIT);
1141
1142 return flowPathsObjArray;
1143 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001144
1145 /**
1146 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1147 *
1148 * @param flowObj the object to extract the Flow Path State from.
1149 * @return the extracted Flow Path State.
1150 */
1151 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001152 //
1153 // Extract the Flow state
1154 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001155 String flowIdStr = flowObj.getFlowId();
1156 String installerIdStr = flowObj.getInstallerId();
1157 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001158 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001159 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001160 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001161
1162 if ((flowIdStr == null) ||
1163 (installerIdStr == null) ||
1164 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001165 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001166 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001167 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001168 // TODO: A work-around, becauuse of some bogus database objects
1169 return null;
1170 }
1171
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001172 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001173 flowPath.setFlowId(new FlowId(flowIdStr));
1174 flowPath.setInstallerId(new CallerId(installerIdStr));
1175 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001176 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001177 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001178 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001179 //
1180 // Extract the match conditions common for all Flow Entries
1181 //
1182 {
1183 FlowEntryMatch match = new FlowEntryMatch();
1184 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1185 if (matchEthernetFrameType != null)
1186 match.enableEthernetFrameType(matchEthernetFrameType);
1187 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1188 if (matchSrcIPv4Net != null)
1189 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1190 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1191 if (matchDstIPv4Net != null)
1192 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1193 String matchSrcMac = flowObj.getMatchSrcMac();
1194 if (matchSrcMac != null)
1195 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1196 String matchDstMac = flowObj.getMatchDstMac();
1197 if (matchDstMac != null)
1198 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1199 flowPath.setFlowEntryMatch(match);
1200 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001201
1202 //
1203 // Extract all Flow Entries
1204 //
1205 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1206 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001207 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1208 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001209 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001210 flowPath.dataPath().flowEntries().add(flowEntry);
1211 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001212
1213 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001214 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001215
1216 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001217 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1218 *
1219 * @param flowEntryObj the object to extract the Flow Entry State from.
1220 * @return the extracted Flow Entry State.
1221 */
1222 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1223 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1224 String switchDpidStr = flowEntryObj.getSwitchDpid();
1225 String userState = flowEntryObj.getUserState();
1226 String switchState = flowEntryObj.getSwitchState();
1227
1228 if ((flowEntryIdStr == null) ||
1229 (switchDpidStr == null) ||
1230 (userState == null) ||
1231 (switchState == null)) {
1232 // TODO: A work-around, becauuse of some bogus database objects
1233 return null;
1234 }
1235
1236 FlowEntry flowEntry = new FlowEntry();
1237 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1238 flowEntry.setDpid(new Dpid(switchDpidStr));
1239
1240 //
1241 // Extract the match conditions
1242 //
1243 FlowEntryMatch match = new FlowEntryMatch();
1244 Short matchInPort = flowEntryObj.getMatchInPort();
1245 if (matchInPort != null)
1246 match.enableInPort(new Port(matchInPort));
1247 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1248 if (matchEthernetFrameType != null)
1249 match.enableEthernetFrameType(matchEthernetFrameType);
1250 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1251 if (matchSrcIPv4Net != null)
1252 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1253 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1254 if (matchDstIPv4Net != null)
1255 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1256 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1257 if (matchSrcMac != null)
1258 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1259 String matchDstMac = flowEntryObj.getMatchDstMac();
1260 if (matchDstMac != null)
1261 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1262 flowEntry.setFlowEntryMatch(match);
1263
1264 //
1265 // Extract the actions
1266 //
1267 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1268 Short actionOutputPort = flowEntryObj.getActionOutput();
1269 if (actionOutputPort != null) {
1270 FlowEntryAction action = new FlowEntryAction();
1271 action.setActionOutput(new Port(actionOutputPort));
1272 actions.add(action);
1273 }
1274 flowEntry.setFlowEntryActions(actions);
1275 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1276 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1277 //
1278 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1279 // and FlowEntryErrorState.
1280 //
1281 return flowEntry;
1282 }
1283
1284 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001285 * Add and maintain a shortest-path flow.
1286 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001287 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001288 *
1289 * @param flowPath the Flow Path with the endpoints and the match
1290 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001291 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001292 */
1293 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001294 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001295 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001296 // Don't do the shortest path computation here.
1297 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001298 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001299
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001300 // We need the DataPath to populate the Network MAP
1301 DataPath dataPath = new DataPath();
1302 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1303 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001304
1305 //
1306 // Prepare the computed Flow Path
1307 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001308 FlowPath computedFlowPath = new FlowPath();
1309 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1310 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1311 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001312 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001313
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001314 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001315 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001316 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001317 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001318
1319 // TODO: Mark the flow for maintenance purpose
1320
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001321 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001322 }
1323
1324 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001325 * Reconcile a flow.
1326 *
1327 * @param flowObj the flow that needs to be reconciliated.
1328 * @param newDataPath the new data path to use.
1329 * @return true on success, otherwise false.
1330 */
1331 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1332 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1333
1334 //
1335 // Set the incoming port matching and the outgoing port output
1336 // actions for each flow entry.
1337 //
1338 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1339 // Set the incoming port matching
1340 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1341 flowEntry.setFlowEntryMatch(flowEntryMatch);
1342 flowEntryMatch.enableInPort(flowEntry.inPort());
1343
1344 // Set the outgoing port output action
1345 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1346 if (flowEntryActions == null) {
1347 flowEntryActions = new ArrayList<FlowEntryAction>();
1348 flowEntry.setFlowEntryActions(flowEntryActions);
1349 }
1350 FlowEntryAction flowEntryAction = new FlowEntryAction();
1351 flowEntryAction.setActionOutput(flowEntry.outPort());
1352 flowEntryActions.add(flowEntryAction);
1353 }
1354
1355 //
1356 // Remove the old Flow Entries, and add the new Flow Entries
1357 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001358 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1359 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1360 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001361 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001362 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001363 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001364 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001365 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001366 }
1367
1368 //
1369 // Set the Data Path Summary
1370 //
1371 String dataPathSummaryStr = newDataPath.dataPathSummary();
1372 flowObj.setDataPathSummary(dataPathSummaryStr);
1373
1374 return true;
1375 }
1376
1377 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001378 * Reconcile all flows in a set.
1379 *
1380 * @param flowObjSet the set of flows that need to be reconciliated.
1381 */
1382 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1383 if (! flowObjSet.iterator().hasNext())
1384 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001385 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001386 }
1387
1388 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001389 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001390 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001391 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001392 * @param flowObj the flow path object for the flow entry to install.
1393 * @param flowEntryObj the flow entry object to install.
1394 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001395 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001396 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1397 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001398 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1399 if (flowEntryIdStr == null)
1400 return false;
1401 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001402 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001403 if (userState == null)
1404 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001405
1406 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001407 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001408 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001409 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1410 .getMessage(OFType.FLOW_MOD);
1411 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001412
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001413 short flowModCommand = OFFlowMod.OFPFC_ADD;
1414 if (userState.equals("FE_USER_ADD")) {
1415 flowModCommand = OFFlowMod.OFPFC_ADD;
1416 } else if (userState.equals("FE_USER_MODIFY")) {
1417 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1418 } else if (userState.equals("FE_USER_DELETE")) {
1419 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1420 } else {
1421 // Unknown user state. Ignore the entry
1422 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1423 flowEntryId.toString(), userState);
1424 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001425 }
1426
1427 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001428 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001429 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001430 // NOTE: The Flow matching conditions common for all Flow Entries are
1431 // used ONLY if a Flow Entry does NOT have the corresponding matching
1432 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001433 //
1434 OFMatch match = new OFMatch();
1435 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001436
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001437 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001438 Short matchInPort = flowEntryObj.getMatchInPort();
1439 if (matchInPort != null) {
1440 match.setInputPort(matchInPort);
1441 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1442 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001443
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001444 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001445 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1446 if (matchEthernetFrameType == null)
1447 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1448 if (matchEthernetFrameType != null) {
1449 match.setDataLayerType(matchEthernetFrameType);
1450 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1451 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001452
1453 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001454 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1455 if (matchSrcIPv4Net == null)
1456 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1457 if (matchSrcIPv4Net != null) {
1458 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1459 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001460
1461 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001462 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1463 if (matchDstIPv4Net == null)
1464 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1465 if (matchDstIPv4Net != null) {
1466 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1467 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001468
1469 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001470 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1471 if (matchSrcMac == null)
1472 matchSrcMac = flowObj.getMatchSrcMac();
1473 if (matchSrcMac != null) {
1474 match.setDataLayerSource(matchSrcMac);
1475 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1476 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001477
1478 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001479 String matchDstMac = flowEntryObj.getMatchDstMac();
1480 if (matchDstMac == null)
1481 matchDstMac = flowObj.getMatchDstMac();
1482 if (matchDstMac != null) {
1483 match.setDataLayerDestination(matchDstMac);
1484 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1485 }
1486
1487 //
1488 // Fetch the actions
1489 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001490 // TODO: For now we support only the "OUTPUT" actions.
1491 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001492 List<OFAction> actions = new ArrayList<OFAction>();
1493 Short actionOutputPort = flowEntryObj.getActionOutput();
1494 if (actionOutputPort != null) {
1495 OFActionOutput action = new OFActionOutput();
1496 // XXX: The max length is hard-coded for now
1497 action.setMaxLength((short)0xffff);
1498 action.setPort(actionOutputPort);
1499 actions.add(action);
1500 }
1501
1502 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1503 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1504 .setPriority(PRIORITY_DEFAULT)
1505 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1506 .setCookie(cookie)
1507 .setCommand(flowModCommand)
1508 .setMatch(match)
1509 .setActions(actions)
1510 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1511 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1512 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1513 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1514 if (actionOutputPort != null)
1515 fm.setOutPort(actionOutputPort);
1516 }
1517
1518 //
1519 // TODO: Set the following flag
1520 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1521 // See method ForwardingBase::pushRoute()
1522 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001523
1524 //
1525 // Write the message to the switch
1526 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001527 log.debug("MEASUREMENT: Installing flow entry " + userState +
1528 " into switch DPID: " +
1529 mySwitch.getStringId() +
1530 " flowEntryId: " + flowEntryId.toString() +
1531 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1532 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1533 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001534 try {
1535 messageDamper.write(mySwitch, fm, null);
1536 mySwitch.flush();
1537 //
1538 // TODO: We should use the OpenFlow Barrier mechanism
1539 // to check for errors, and update the SwitchState
1540 // for a flow entry after the Barrier message is
1541 // is received.
1542 //
1543 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1544 } catch (IOException e) {
1545 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001546 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001547 }
1548
1549 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001550 }
1551
1552 /**
1553 * Install a Flow Entry on a switch.
1554 *
1555 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001556 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001557 * @param flowEntry the flow entry to install.
1558 * @return true on success, otherwise false.
1559 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001560 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1561 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001562 //
1563 // Create the OpenFlow Flow Modification Entry to push
1564 //
1565 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1566 .getMessage(OFType.FLOW_MOD);
1567 long cookie = flowEntry.flowEntryId().value();
1568
1569 short flowModCommand = OFFlowMod.OFPFC_ADD;
1570 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1571 flowModCommand = OFFlowMod.OFPFC_ADD;
1572 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1573 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1574 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1575 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1576 } else {
1577 // Unknown user state. Ignore the entry
1578 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1579 flowEntry.flowEntryId().toString(),
1580 flowEntry.flowEntryUserState());
1581 return false;
1582 }
1583
1584 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001585 // Fetch the match conditions.
1586 //
1587 // NOTE: The Flow matching conditions common for all Flow Entries are
1588 // used ONLY if a Flow Entry does NOT have the corresponding matching
1589 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001590 //
1591 OFMatch match = new OFMatch();
1592 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001593 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1594 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1595
1596 // Match the Incoming Port
1597 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001598 if (matchInPort != null) {
1599 match.setInputPort(matchInPort.value());
1600 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1601 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001602
1603 // Match the Ethernet Frame Type
1604 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1605 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1606 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1607 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001608 if (matchEthernetFrameType != null) {
1609 match.setDataLayerType(matchEthernetFrameType);
1610 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1611 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001612
1613 // Match the Source IPv4 Network prefix
1614 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1615 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1616 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1617 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001618 if (matchSrcIPv4Net != null) {
1619 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1620 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001621
1622 // Natch the Destination IPv4 Network prefix
1623 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1624 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1625 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1626 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001627 if (matchDstIPv4Net != null) {
1628 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1629 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001630
1631 // Match the Source MAC address
1632 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1633 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1634 matchSrcMac = flowPathMatch.srcMac();
1635 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001636 if (matchSrcMac != null) {
1637 match.setDataLayerSource(matchSrcMac.toString());
1638 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1639 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001640
1641 // Match the Destination MAC address
1642 MACAddress matchDstMac = flowEntryMatch.dstMac();
1643 if ((matchDstMac == null) && (flowPathMatch != null)) {
1644 matchDstMac = flowPathMatch.dstMac();
1645 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001646 if (matchDstMac != null) {
1647 match.setDataLayerDestination(matchDstMac.toString());
1648 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1649 }
1650
1651 //
1652 // Fetch the actions
1653 //
1654 // TODO: For now we support only the "OUTPUT" actions.
1655 //
1656 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1657 List<OFAction> actions = new ArrayList<OFAction>();
1658 ArrayList<FlowEntryAction> flowEntryActions =
1659 flowEntry.flowEntryActions();
1660 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1661 FlowEntryAction.ActionOutput actionOutput =
1662 flowEntryAction.actionOutput();
1663 if (actionOutput != null) {
1664 short actionOutputPort = actionOutput.port().value();
1665 OFActionOutput action = new OFActionOutput();
1666 // XXX: The max length is hard-coded for now
1667 action.setMaxLength((short)0xffff);
1668 action.setPort(actionOutputPort);
1669 actions.add(action);
1670 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1671 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1672 fm.setOutPort(actionOutputPort);
1673 }
1674 }
1675 }
1676
1677 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1678 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1679 .setPriority(PRIORITY_DEFAULT)
1680 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1681 .setCookie(cookie)
1682 .setCommand(flowModCommand)
1683 .setMatch(match)
1684 .setActions(actions)
1685 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1686
1687 //
1688 // TODO: Set the following flag
1689 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1690 // See method ForwardingBase::pushRoute()
1691 //
1692
1693 //
1694 // Write the message to the switch
1695 //
1696 try {
1697 messageDamper.write(mySwitch, fm, null);
1698 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001699 //
1700 // TODO: We should use the OpenFlow Barrier mechanism
1701 // to check for errors, and update the SwitchState
1702 // for a flow entry after the Barrier message is
1703 // is received.
1704 //
1705 // TODO: The FlowEntry Object in Titan should be set
1706 // to FE_SWITCH_UPDATED.
1707 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001708 } catch (IOException e) {
1709 log.error("Failure writing flow mod from network map", e);
1710 return false;
1711 }
1712 return true;
1713 }
1714
1715 /**
1716 * Remove a Flow Entry from a switch.
1717 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001718 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001719 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001720 * @param flowEntry the flow entry to remove.
1721 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001722 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001723 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1724 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001725 //
1726 // The installFlowEntry() method implements both installation
1727 // and removal of flow entries.
1728 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001729 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001730 }
1731
1732 /**
1733 * Install a Flow Entry on a remote controller.
1734 *
1735 * TODO: We need it now: Jono
1736 * - For now it will make a REST call to the remote controller.
1737 * - Internally, it needs to know the name of the remote controller.
1738 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001739 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001740 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001741 * @return true on success, otherwise false.
1742 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001743 public boolean installRemoteFlowEntry(FlowPath flowPath,
1744 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001745 // TODO: We need it now: Jono
1746 // - For now it will make a REST call to the remote controller.
1747 // - Internally, it needs to know the name of the remote controller.
1748 return true;
1749 }
1750
1751 /**
1752 * Remove a flow entry on a remote controller.
1753 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001754 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001755 * @param flowEntry the flow entry to remove.
1756 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001757 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001758 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1759 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001760 //
1761 // The installRemoteFlowEntry() method implements both installation
1762 // and removal of flow entries.
1763 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001764 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001765 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001766}