blob: 012f33313c3381d27879008b64e67463a0f1846c [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
3import java.util.ArrayList;
4import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08005import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00007import java.util.LinkedList;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00009import java.util.Random;
Pavlin Radoslavov3f9ba652013-10-25 17:19:01 -070010import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.concurrent.Executors;
Pavlin Radoslavov3f9ba652013-10-25 17:19:01 -070012import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080015
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080018import net.floodlightcontroller.core.module.FloodlightModuleContext;
19import net.floodlightcontroller.core.module.FloodlightModuleException;
20import net.floodlightcontroller.core.module.IFloodlightModule;
21import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080023import net.floodlightcontroller.util.OFMessageDamper;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070024
25import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070026import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070027import net.onrc.onos.ofcontroller.core.INetMapStorage;
28import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
29import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070030import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070031import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070032import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070033import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070034import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
admin944ef4f2013-10-08 17:48:37 -070040/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070041 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070042 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070043public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070045 protected GraphDBOperation dbHandler;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080046
Jonathan Hart50a94982013-04-10 14:49:51 -070047 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070048 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070049 protected volatile IDatagridService datagridService;
50 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070051 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052
53 protected OFMessageDamper messageDamper;
54
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070055 //
56 // TODO: Values copied from elsewhere (class LearningSwitch).
57 // The local copy should go away!
58 //
59 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
60 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080061
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000062 // Flow Entry ID generation state
63 private static Random randomGenerator = new Random();
64 private static int nextFlowEntryIdPrefix = 0;
65 private static int nextFlowEntryIdSuffix = 0;
66 private static long nextFlowEntryId = 0;
67
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080068 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070069 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -070072 private ScheduledExecutorService mapReaderScheduler;
73 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -070074
Pavlin Radoslavov3f9ba652013-10-25 17:19:01 -070075 // The queue with Flow Path updates
76 protected BlockingQueue<EventEntry<FlowPath>> flowPathEvents =
77 new LinkedBlockingQueue<EventEntry<FlowPath>>();
78
admin944ef4f2013-10-08 17:48:37 -070079 /**
80 * Periodic task for reading the Flow Entries and pushing changes
81 * into the switches.
82 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070083 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080084 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070085 try {
86 runImpl();
87 } catch (Exception e) {
88 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070089 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -070090 return;
91 }
92 }
93
94 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070095 long startTime = System.nanoTime();
96 int counterAllFlowEntries = 0;
97 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -070098
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080099 if (floodlightProvider == null) {
100 log.debug("FloodlightProvider service not found!");
101 return;
102 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000103 Map<Long, IOFSwitch> mySwitches =
104 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700105 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700106 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700107 return;
108 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700109 LinkedList<IFlowEntry> addFlowEntries =
110 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000111 LinkedList<IFlowEntry> deleteFlowEntries =
112 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700113
114 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700115 // Fetch all Flow Entries which need to be updated and select
116 // only my Flow Entries that need to be updated into the
117 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700118 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000119 Iterable<IFlowEntry> allFlowEntries =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700120 dbHandler.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700121 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700122 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000123
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000124 String dpidStr = flowEntryObj.getSwitchDpid();
125 if (dpidStr == null)
126 continue;
127 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800128 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000129 if (mySwitch == null)
130 continue; // Ignore the entry: not my switch
131
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700132 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700133 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700134 if (flowObj == null)
135 continue; // Should NOT happen
136 if (flowObj.getFlowId() == null)
137 continue; // Invalid entry
138
139 //
140 // NOTE: For now we process the DELETE before the ADD
141 // to cover the more common scenario.
142 // TODO: This is error prone and needs to be fixed!
143 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000144 String userState = flowEntryObj.getUserState();
145 if (userState == null)
146 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700147 if (userState.equals("FE_USER_DELETE")) {
148 // An entry that needs to be deleted.
149 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700150 installFlowEntry(mySwitch, flowObj, flowEntryObj);
151 } else {
152 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700153 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700154 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700155 }
156
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700157 //
158 // Process the Flow Entries that need to be added
159 //
160 for (IFlowEntry flowEntryObj : addFlowEntries) {
161 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700162 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700163 if (flowObj == null)
164 continue; // Should NOT happen
165 if (flowObj.getFlowId() == null)
166 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700167
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700168 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700169 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000170 if (mySwitch == null)
171 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700172 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800173 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000174
175 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000176 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700177 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000178 //
179 // TODO: We should use the OpenFlow Barrier mechanism
180 // to check for errors, and delete the Flow Entries after the
181 // Barrier message is received.
182 //
183 while (! deleteFlowEntries.isEmpty()) {
184 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
185 IFlowPath flowObj =
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700186 dbHandler.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000187 if (flowObj == null) {
188 log.debug("Did not find FlowPath to be deleted");
189 continue;
190 }
191 flowObj.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700192 dbHandler.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000193 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700194
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700195 dbHandler.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700196
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700197 long estimatedTime = System.nanoTime() - startTime;
198 double rate = 0.0;
199 if (estimatedTime > 0)
200 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
201 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
202 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
203 counterMyNotUpdatedFlowEntries + " in " +
204 (double)estimatedTime / 1000000000 + " sec: " +
205 rate + " paths/s";
206 log.debug(logMsg);
207 }
208 };
209
admin944ef4f2013-10-08 17:48:37 -0700210 /**
211 * Periodic task for reading the Flow Paths and recomputing the
212 * shortest paths.
213 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700214 final Runnable shortestPathReconcile = new Runnable() {
215 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700216 try {
217 runImpl();
218 } catch (Exception e) {
219 log.debug("Exception processing All Flows from the Network MAP: ", e);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700220 dbHandler.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700221 return;
222 }
223 }
224
225 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700226 long startTime = System.nanoTime();
227 int counterAllFlowPaths = 0;
228 int counterMyFlowPaths = 0;
229
230 if (floodlightProvider == null) {
231 log.debug("FloodlightProvider service not found!");
232 return;
233 }
234 Map<Long, IOFSwitch> mySwitches =
235 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700236 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700237 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700238 return;
239 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700240 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
241
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700242 //
243 // Fetch and recompute the Shortest Path for those
244 // Flow Paths this controller is responsible for.
245 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700246 Topology topology = topologyNetService.newDatabaseTopology();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700247 Iterable<IFlowPath> allFlowPaths = dbHandler.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700248 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700249 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700250 if (flowPathObj == null)
251 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700252
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700253 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000254 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700255 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700256 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700257 //
258 // Use the source DPID as a heuristic to decide
259 // which controller is responsible for maintaining the
260 // shortest path.
261 // NOTE: This heuristic is error-prone: if the switch
262 // goes away and no controller is responsible for that
263 // switch, then the original Flow Path is not cleaned-up
264 //
265 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
266 if (mySwitch == null)
267 continue; // Ignore: not my responsibility
268
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700269 // Test the Data Path Summary string
270 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
271 if (dataPathSummaryStr == null)
272 continue; // Could be invalid entry?
273 if (dataPathSummaryStr.isEmpty())
274 continue; // No need to maintain this flow
275
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000276 //
277 // Test whether we need to complete the Flow cleanup,
278 // if the Flow has been deleted by the user.
279 //
280 String flowUserState = flowPathObj.getUserState();
281 if ((flowUserState != null)
282 && flowUserState.equals("FE_USER_DELETE")) {
283 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700284 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000285 if (empty)
286 deleteFlows.add(flowPathObj);
287 }
288
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000289 // Fetch the fields needed to recompute the shortest path
290 Short srcPortShort = flowPathObj.getSrcPort();
291 String dstDpidStr = flowPathObj.getDstSwitch();
292 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700293 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000294 if ((srcPortShort == null) ||
295 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700296 (dstPortShort == null) ||
297 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000298 continue;
299 }
300
301 Port srcPort = new Port(srcPortShort);
302 Dpid dstDpid = new Dpid(dstDpidStr);
303 Port dstPort = new Port(dstPortShort);
304 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
305 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700306 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000307
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700308 counterMyFlowPaths++;
309
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700310 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700311 // NOTE: Using here the regular getDatabaseShortestPath()
312 // method won't work here, because that method calls
313 // internally "conn.endTx(Transaction.COMMIT)", and that
314 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700315 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700316 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700317 // to avoid closing the transaction.
318 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700319 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700320 topologyNetService.getTopologyShortestPath(
321 topology,
322 srcSwitchPort,
323 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000324 if (dataPath == null) {
325 // We need the DataPath to compare the paths
326 dataPath = new DataPath();
327 dataPath.setSrcPort(srcSwitchPort);
328 dataPath.setDstPort(dstSwitchPort);
329 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700330 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000331
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700332 String newDataPathSummaryStr = dataPath.dataPathSummary();
333 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
334 continue; // Nothing changed
335
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700336 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700337 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000338
339 //
340 // Delete all leftover Flows marked for deletion from the
341 // Network MAP.
342 //
343 while (! deleteFlows.isEmpty()) {
344 IFlowPath flowPathObj = deleteFlows.poll();
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700345 dbHandler.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000346 }
347
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700348 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700349
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700350 dbHandler.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700351
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700352 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700353 double rate = 0.0;
354 if (estimatedTime > 0)
355 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700356 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700357 counterAllFlowPaths + " MyFlowPaths: " +
358 counterMyFlowPaths + " in " +
359 (double)estimatedTime / 1000000000 + " sec: " +
360 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700361 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800362 }
363 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700364
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800365
admin944ef4f2013-10-08 17:48:37 -0700366 /**
367 * Initialize the Flow Manager.
368 *
369 * @param conf the Graph Database configuration string.
370 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800371 @Override
372 public void init(String conf) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700373 dbHandler = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800374 }
375
admin944ef4f2013-10-08 17:48:37 -0700376 /**
377 * Shutdown the Flow Manager operation.
378 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800379 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700380 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800381 }
382
admin944ef4f2013-10-08 17:48:37 -0700383 /**
384 * Shutdown the Flow Manager operation.
385 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800386 @Override
387 public void close() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700388 datagridService.deregisterFlowService(this);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700389 dbHandler.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800390 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800391
admin944ef4f2013-10-08 17:48:37 -0700392 /**
393 * Get the collection of offered module services.
394 *
395 * @return the collection of offered module services.
396 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800397 @Override
398 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
399 Collection<Class<? extends IFloodlightService>> l =
400 new ArrayList<Class<? extends IFloodlightService>>();
401 l.add(IFlowService.class);
402 return l;
403 }
404
admin944ef4f2013-10-08 17:48:37 -0700405 /**
406 * Get the collection of implemented services.
407 *
408 * @return the collection of implemented services.
409 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800410 @Override
411 public Map<Class<? extends IFloodlightService>, IFloodlightService>
412 getServiceImpls() {
413 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700414 IFloodlightService> m =
415 new HashMap<Class<? extends IFloodlightService>,
416 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800417 m.put(IFlowService.class, this);
418 return m;
419 }
420
admin944ef4f2013-10-08 17:48:37 -0700421 /**
422 * Get the collection of modules this module depends on.
423 *
424 * @return the collection of modules this module depends on.
425 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800426 @Override
427 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700428 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800429 Collection<Class<? extends IFloodlightService>> l =
430 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800431 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700432 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700433 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800434 l.add(IRestApiService.class);
435 return l;
436 }
437
admin944ef4f2013-10-08 17:48:37 -0700438 /**
439 * Initialize the module.
440 *
441 * @param context the module context to use for the initialization.
442 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800443 @Override
444 public void init(FloodlightModuleContext context)
445 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700446 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700448 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
449 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800450 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700451
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
453 EnumSet.of(OFType.FLOW_MOD),
454 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700455
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700456 this.init("");
457
admin944ef4f2013-10-08 17:48:37 -0700458 mapReaderScheduler = Executors.newScheduledThreadPool(1);
459 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800460 }
461
admin944ef4f2013-10-08 17:48:37 -0700462 /**
463 * Get the next Flow Entry ID to use.
464 *
465 * @return the next Flow Entry ID to use.
466 */
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700467 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000468 //
469 // Generate the next Flow Entry ID.
470 // NOTE: For now, the higher 32 bits are random, and
471 // the lower 32 bits are sequential.
472 // In the future, we need a better allocation mechanism.
473 //
474 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
475 nextFlowEntryIdPrefix = randomGenerator.nextInt();
476 nextFlowEntryIdSuffix = 0;
477 } else {
478 nextFlowEntryIdSuffix++;
479 }
480 long result = (long)nextFlowEntryIdPrefix << 32;
481 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
482 return result;
483 }
484
admin944ef4f2013-10-08 17:48:37 -0700485 /**
486 * Startup module operation.
487 *
488 * @param context the module context to use for the startup.
489 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800490 @Override
491 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700492 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700493
admin944ef4f2013-10-08 17:48:37 -0700494 // Initialize the Flow Entry ID generator
495 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700496
Pavlin Radoslavov3f9ba652013-10-25 17:19:01 -0700497 // Register with the Datagrid Service and obtain the initial state
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700498 datagridService.registerFlowService(this);
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700499 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
Pavlin Radoslavov3f9ba652013-10-25 17:19:01 -0700500 for (FlowPath flowPath : flowPaths) {
501 EventEntry<FlowPath> eventEntry =
502 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
503 flowPathEvents.add(eventEntry);
504 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700505
Pavlin Radoslavov3f9ba652013-10-25 17:19:01 -0700506 // Schedule the periodic tasks
admin944ef4f2013-10-08 17:48:37 -0700507 mapReaderScheduler.scheduleAtFixedRate(
508 mapReader, 3, 3, TimeUnit.SECONDS);
509 shortestPathReconcileScheduler.scheduleAtFixedRate(
510 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800511 }
512
513 /**
514 * Add a flow.
515 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800516 * @param flowPath the Flow Path to install.
517 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700518 * @param dataPathSummaryStr the data path summary string if the added
519 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800520 * @return true on success, otherwise false.
521 */
522 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700523 public boolean addFlow(FlowPath flowPath, FlowId flowId,
524 String dataPathSummaryStr) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700525 if (FlowDatabaseOperation.addFlow(this, dbHandler, flowPath, flowId,
526 dataPathSummaryStr)) {
527 datagridService.notificationSendFlowAdded(flowPath);
528 return true;
529 }
530 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800531 }
532
533 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700534 * Add a flow entry to the Network MAP.
535 *
536 * @param flowObj the corresponding Flow Path object for the Flow Entry.
537 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700538 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700539 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700540 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700541 return FlowDatabaseOperation.addFlowEntry(this, dbHandler, flowObj,
542 flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700543 }
544
545 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000546 * Delete all previously added flows.
547 *
548 * @return true on success, otherwise false.
549 */
550 @Override
551 public boolean deleteAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700552 if (FlowDatabaseOperation.deleteAllFlows(dbHandler)) {
553 datagridService.notificationSendAllFlowsRemoved();
554 return true;
555 }
556 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000557 }
558
559 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800560 * Delete a previously added flow.
561 *
562 * @param flowId the Flow ID of the flow to delete.
563 * @return true on success, otherwise false.
564 */
565 @Override
566 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700567 if (FlowDatabaseOperation.deleteFlow(dbHandler, flowId)) {
568 datagridService.notificationSendFlowRemoved(flowId);
569 return true;
570 }
571 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800572 }
573
574 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000575 * Clear the state for all previously added flows.
576 *
577 * @return true on success, otherwise false.
578 */
579 @Override
580 public boolean clearAllFlows() {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700581 if (FlowDatabaseOperation.clearAllFlows(dbHandler)) {
582 datagridService.notificationSendAllFlowsRemoved();
583 return true;
584 }
585 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000586 }
587
588 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700589 * Clear the state for a previously added flow.
590 *
591 * @param flowId the Flow ID of the flow to clear.
592 * @return true on success, otherwise false.
593 */
594 @Override
595 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700596 if (FlowDatabaseOperation.clearFlow(dbHandler, flowId)) {
597 datagridService.notificationSendFlowRemoved(flowId);
598 return true;
599 }
600 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700601 }
602
603 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800604 * Get a previously added flow.
605 *
606 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800607 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800608 */
609 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800610 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700611 return FlowDatabaseOperation.getFlow(dbHandler, flowId);
612 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800613
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700614 /**
615 * Get all installed flows by all installers.
616 *
617 * @return the Flow Paths if found, otherwise null.
618 */
619 @Override
620 public ArrayList<FlowPath> getAllFlows() {
621 return FlowDatabaseOperation.getAllFlows(dbHandler);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800622 }
623
624 /**
625 * Get all previously added flows by a specific installer for a given
626 * data path endpoints.
627 *
628 * @param installerId the Caller ID of the installer of the flow to get.
629 * @param dataPathEndpoints the data path endpoints of the flow to get.
630 * @return the Flow Paths if found, otherwise null.
631 */
632 @Override
633 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
634 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700635 return FlowDatabaseOperation.getAllFlows(dbHandler, installerId,
636 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800637 }
638
639 /**
640 * Get all installed flows by all installers for given data path endpoints.
641 *
642 * @param dataPathEndpoints the data path endpoints of the flows to get.
643 * @return the Flow Paths if found, otherwise null.
644 */
645 @Override
646 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700647 return FlowDatabaseOperation.getAllFlows(dbHandler, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800648 }
649
650 /**
admin944ef4f2013-10-08 17:48:37 -0700651 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700652 *
admin944ef4f2013-10-08 17:48:37 -0700653 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700654 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700655 * @return the Flow Paths if found, otherwise null.
656 */
657 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700658 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
659 int maxFlows) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700660 return FlowDatabaseOperation.getAllFlowsSummary(dbHandler, flowId,
661 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700662 }
663
664 /**
admin944ef4f2013-10-08 17:48:37 -0700665 * Get all Flows information, without the associated Flow Entries.
666 *
667 * @return all Flows information, without the associated Flow Entries.
668 */
669 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700670 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandler);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700671 }
672
673 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700674 * Add and maintain a shortest-path flow.
675 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700676 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700677 *
678 * @param flowPath the Flow Path with the endpoints and the match
679 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700680 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700681 */
682 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700683 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700684 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000685 // Don't do the shortest path computation here.
686 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700687 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700688
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000689 // We need the DataPath to populate the Network MAP
690 DataPath dataPath = new DataPath();
691 dataPath.setSrcPort(flowPath.dataPath().srcPort());
692 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700693
694 //
695 // Prepare the computed Flow Path
696 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700697 FlowPath computedFlowPath = new FlowPath();
698 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
699 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700700 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700701 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700702 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700703 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700704
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700705 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000706 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700707 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700708 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700709
710 // TODO: Mark the flow for maintenance purpose
711
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700712 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700713 }
714
715 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700716 * Reconcile a flow.
717 *
718 * @param flowObj the flow that needs to be reconciliated.
719 * @param newDataPath the new data path to use.
720 * @return true on success, otherwise false.
721 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700722 private boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700723
724 //
725 // Set the incoming port matching and the outgoing port output
726 // actions for each flow entry.
727 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700728 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700729 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
730 // Set the incoming port matching
731 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
732 flowEntry.setFlowEntryMatch(flowEntryMatch);
733 flowEntryMatch.enableInPort(flowEntry.inPort());
734
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700735 //
736 // Set the actions
737 //
738 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
739 //
740 // If the first Flow Entry, copy the Flow Path actions to it
741 //
742 if (idx == 0) {
743 String actionsStr = flowObj.getActions();
744 if (actionsStr != null) {
745 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
746 for (FlowEntryAction action : flowActions.actions())
747 flowEntryActions.addAction(action);
748 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700749 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -0700750 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700751 //
752 // Add the outgoing port output action
753 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700754 FlowEntryAction flowEntryAction = new FlowEntryAction();
755 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700756 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700757 }
758
759 //
760 // Remove the old Flow Entries, and add the new Flow Entries
761 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700762 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700763 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700764 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700765 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700766 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700767 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700768 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700769 }
770
771 //
772 // Set the Data Path Summary
773 //
774 String dataPathSummaryStr = newDataPath.dataPathSummary();
775 flowObj.setDataPathSummary(dataPathSummaryStr);
776
777 return true;
778 }
779
780 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700781 * Reconcile all flows in a set.
782 *
783 * @param flowObjSet the set of flows that need to be reconciliated.
784 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700785 private void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700786 if (! flowObjSet.iterator().hasNext())
787 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -0700788 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700789 }
790
791 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700792 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700793 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700794 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700795 * @param flowObj the flow path object for the flow entry to install.
796 * @param flowEntryObj the flow entry object to install.
797 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700798 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700799 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700800 IFlowEntry flowEntryObj) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700801 return FlowSwitchOperation.installFlowEntry(
802 floodlightProvider.getOFMessageFactory(),
803 messageDamper, mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700804 }
805
806 /**
807 * Install a Flow Entry on a switch.
808 *
809 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700810 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700811 * @param flowEntry the flow entry to install.
812 * @return true on success, otherwise false.
813 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700814 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700815 FlowEntry flowEntry) {
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700816 return FlowSwitchOperation.installFlowEntry(
817 floodlightProvider.getOFMessageFactory(),
818 messageDamper, mySwitch, flowPath, flowEntry);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700819 }
820
821 /**
822 * Remove a Flow Entry from a switch.
823 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700824 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700825 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700826 * @param flowEntry the flow entry to remove.
827 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700828 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700829 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700830 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700831 //
832 // The installFlowEntry() method implements both installation
833 // and removal of flow entries.
834 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700835 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700836 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700837
838 /**
839 * Receive a notification that a Flow is added.
840 *
841 * @param flowPath the flow that is added.
842 */
843 @Override
844 public void notificationRecvFlowAdded(FlowPath flowPath) {
845 // TODO
846 }
847
848 /**
849 * Receive a notification that a Flow is removed.
850 *
851 * @param flowPath the flow that is removed.
852 */
853 @Override
854 public void notificationRecvFlowRemoved(FlowPath flowPath) {
855 // TODO
856 }
857
858 /**
859 * Receive a notification that a Flow is updated.
860 *
861 * @param flowPath the flow that is updated.
862 */
863 @Override
864 public void notificationRecvFlowUpdated(FlowPath flowPath) {
865 // TODO
866 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800867}