blob: dcd683d4ad9932b20bbff3c3d4d97d254a6a1489 [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;
5import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00006import java.util.LinkedList;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00008import java.util.Random;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -08009import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080010import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080016import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070021import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070022import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070023import net.onrc.onos.ofcontroller.core.INetMapStorage;
24import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
25import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070026import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070027import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080028import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070029import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070030import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080031
Naoki Shiota1a37ca12013-11-18 10:55:23 -080032import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
admin944ef4f2013-10-08 17:48:37 -070036/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070037 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070038 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070039public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080040 protected GraphDBOperation dbHandlerApi;
41 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080042
Jonathan Hart50a94982013-04-10 14:49:51 -070043 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070044 protected volatile IDatagridService datagridService;
45 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070046 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070047 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080048
Brian O'Connor8c166a72013-11-14 18:41:48 -080049 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080050
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000051 // Flow Entry ID generation state
52 private static Random randomGenerator = new Random();
53 private static int nextFlowEntryIdPrefix = 0;
54 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000055
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080056 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070057 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080058
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080059 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080060 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
61 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080062 FlowDatabaseWriter flowDatabaseWriter;
63
admin944ef4f2013-10-08 17:48:37 -070064 /**
65 * Initialize the Flow Manager.
66 *
67 * @param conf the Graph Database configuration string.
68 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080069 @Override
70 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080071 dbHandlerApi = new GraphDBOperation(conf);
72 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080073 }
74
admin944ef4f2013-10-08 17:48:37 -070075 /**
76 * Shutdown the Flow Manager operation.
77 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070079 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080080 }
81
admin944ef4f2013-10-08 17:48:37 -070082 /**
83 * Shutdown the Flow Manager operation.
84 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080085 @Override
86 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070087 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080088 dbHandlerApi.close();
89 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080090 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080091
admin944ef4f2013-10-08 17:48:37 -070092 /**
93 * Get the collection of offered module services.
94 *
95 * @return the collection of offered module services.
96 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080097 @Override
98 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
99 Collection<Class<? extends IFloodlightService>> l =
100 new ArrayList<Class<? extends IFloodlightService>>();
101 l.add(IFlowService.class);
102 return l;
103 }
104
admin944ef4f2013-10-08 17:48:37 -0700105 /**
106 * Get the collection of implemented services.
107 *
108 * @return the collection of implemented services.
109 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800110 @Override
111 public Map<Class<? extends IFloodlightService>, IFloodlightService>
112 getServiceImpls() {
113 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700114 IFloodlightService> m =
115 new HashMap<Class<? extends IFloodlightService>,
116 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800117 m.put(IFlowService.class, this);
118 return m;
119 }
120
admin944ef4f2013-10-08 17:48:37 -0700121 /**
122 * Get the collection of modules this module depends on.
123 *
124 * @return the collection of modules this module depends on.
125 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800126 @Override
127 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700128 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800129 Collection<Class<? extends IFloodlightService>> l =
130 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800131 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700132 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700133 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800134 l.add(IRestApiService.class);
135 return l;
136 }
137
admin944ef4f2013-10-08 17:48:37 -0700138 /**
139 * Initialize the module.
140 *
141 * @param context the module context to use for the initialization.
142 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800143 @Override
144 public void init(FloodlightModuleContext context)
145 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700146 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800147 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700148 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800149 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800150 pusher = context.getServiceImpl(IFlowPusherService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800151
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700152 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800153 }
154
admin944ef4f2013-10-08 17:48:37 -0700155 /**
156 * Get the next Flow Entry ID to use.
157 *
158 * @return the next Flow Entry ID to use.
159 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800160 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700161 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000162 //
163 // Generate the next Flow Entry ID.
164 // NOTE: For now, the higher 32 bits are random, and
165 // the lower 32 bits are sequential.
166 // In the future, we need a better allocation mechanism.
167 //
168 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
169 nextFlowEntryIdPrefix = randomGenerator.nextInt();
170 nextFlowEntryIdSuffix = 0;
171 } else {
172 nextFlowEntryIdSuffix++;
173 }
174 long result = (long)nextFlowEntryIdPrefix << 32;
175 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
176 return result;
177 }
178
admin944ef4f2013-10-08 17:48:37 -0700179 /**
180 * Startup module operation.
181 *
182 * @param context the module context to use for the startup.
183 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800184 @Override
185 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700186 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700187
admin944ef4f2013-10-08 17:48:37 -0700188 // Initialize the Flow Entry ID generator
189 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800190
191 //
192 // The thread to write to the database
193 //
194 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800195 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800196 flowDatabaseWriter.start();
197
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700198 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800199 // The Flow Event Handler thread:
200 // - create
201 // - register with the Datagrid Service
202 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700203 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700204 flowEventHandler = new FlowEventHandler(this, datagridService);
205 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700206 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800207 }
208
209 /**
210 * Add a flow.
211 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800212 * @param flowPath the Flow Path to install.
213 * @param flowId the return-by-reference Flow ID as assigned internally.
214 * @return true on success, otherwise false.
215 */
216 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700217 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700218 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700219 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700220 // in case the application didn't do it.
221 //
222 for (FlowEntry flowEntry : flowPath.flowEntries()) {
223 if (flowEntry.flowEntrySwitchState() ==
224 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
225 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
226 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700227 if (! flowEntry.isValidFlowId())
228 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700229 }
230
Pavlin Radoslavov67bf7622013-12-04 12:28:23 -0800231 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700232 datagridService.notificationSendFlowAdded(flowPath);
233 return true;
234 }
235 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800236 }
237
238 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700239 * Add a flow entry to the Network MAP.
240 *
241 * @param flowObj the corresponding Flow Path object for the Flow Entry.
242 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700243 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700244 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700245 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov67bf7622013-12-04 12:28:23 -0800246 return FlowDatabaseOperation.addFlowEntry(dbHandlerInner, flowObj,
247 flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700248 }
249
250 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700251 * Delete a flow entry from the Network MAP.
252 *
253 * @param flowObj the corresponding Flow Path object for the Flow Entry.
254 * @param flowEntry the Flow Entry to delete.
255 * @return true on success, otherwise false.
256 */
257 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800258 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
259 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800260 }
261
262 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000263 * Delete all previously added flows.
264 *
265 * @return true on success, otherwise false.
266 */
267 @Override
268 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800269 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700270 datagridService.notificationSendAllFlowsRemoved();
271 return true;
272 }
273 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000274 }
275
276 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800277 * Delete a previously added flow.
278 *
279 * @param flowId the Flow ID of the flow to delete.
280 * @return true on success, otherwise false.
281 */
282 @Override
283 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800284 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700285 datagridService.notificationSendFlowRemoved(flowId);
286 return true;
287 }
288 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700289 }
290
291 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800292 * Get a previously added flow.
293 *
294 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800295 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800296 */
297 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800298 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800299 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700300 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800301
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700302 /**
303 * Get all installed flows by all installers.
304 *
305 * @return the Flow Paths if found, otherwise null.
306 */
307 @Override
308 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800309 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800310 }
311
312 /**
313 * Get all previously added flows by a specific installer for a given
314 * data path endpoints.
315 *
316 * @param installerId the Caller ID of the installer of the flow to get.
317 * @param dataPathEndpoints the data path endpoints of the flow to get.
318 * @return the Flow Paths if found, otherwise null.
319 */
320 @Override
321 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
322 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800323 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700324 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800325 }
326
327 /**
328 * Get all installed flows by all installers for given data path endpoints.
329 *
330 * @param dataPathEndpoints the data path endpoints of the flows to get.
331 * @return the Flow Paths if found, otherwise null.
332 */
333 @Override
334 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800335 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
336 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800337 }
338
339 /**
admin944ef4f2013-10-08 17:48:37 -0700340 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700341 *
admin944ef4f2013-10-08 17:48:37 -0700342 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700343 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700344 * @return the Flow Paths if found, otherwise null.
345 */
346 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800347 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
348 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800349 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700350 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700351 }
352
353 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700354 * Add and maintain a shortest-path flow.
355 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700356 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700357 *
358 * @param flowPath the Flow Path with the endpoints and the match
359 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700360 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700361 */
362 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700363 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700364 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000365 // Don't do the shortest path computation here.
366 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700367 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700368
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700369 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700370 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700371 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700372
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700373 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700374 }
375
376 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800377 * Get the collection of my switches.
378 *
379 * @return the collection of my switches.
380 */
381 public Map<Long, IOFSwitch> getMySwitches() {
382 return floodlightProvider.getSwitches();
383 }
384
385 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800386 * Get the network topology.
387 *
388 * @return the network topology.
389 */
390 public Topology getTopology() {
391 return flowEventHandler.getTopology();
392 }
393
394 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800395 * Inform the Flow Manager that a Flow Entry on switch expired.
396 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800397 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800398 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
399 */
Brian O'Connor4f0b60c2013-11-26 15:00:04 -0800400 public void flowEntryOnSwitchExpired(IOFSwitch sw, FlowEntryId flowEntryId) {
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800401 // TODO: Not implemented yet
402 }
403
404 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800405 * Inform the Flow Manager that a Flow Entry has been pushed to a switch.
406 *
407 * @param sw the switch the Flow Entry has been pushed to.
408 * @param flowEntry the Flow Entry that has been pushed.
409 */
410 public void flowEntryPushedToSwitch(IOFSwitch sw, FlowEntry flowEntry) {
411 //
412 // Mark the Flow Entry that it has been pushed to the switch
413 //
414 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
415
416 //
417 // Write the Flow Entry to the Datagrid
418 //
419 switch (flowEntry.flowEntryUserState()) {
420 case FE_USER_ADD:
421 datagridService.notificationSendFlowEntryAdded(flowEntry);
422 break;
423 case FE_USER_MODIFY:
424 datagridService.notificationSendFlowEntryUpdated(flowEntry);
425 break;
426 case FE_USER_DELETE:
427 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
428 break;
429 }
430 }
431
432 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800433 * Push modified Flow-related state as appropriate.
434 *
435 * @param modifiedFlowPaths the collection of modified Flow Paths.
436 * @param modifiedFlowEntries the collection of modified Flow Entries.
437 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800438 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
439 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800440 //
441 // Push the modified Flow state:
442 // - Flow Entries to switches and the datagrid
443 // - Flow Paths to the database
444 //
445 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800446 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800447 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800448 }
449
450 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800451 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700452 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800453 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700454 * are pushed.
455 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800456 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700457 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800458 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800459 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800460 if (modifiedFlowEntries.isEmpty())
461 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700462
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800463 Map<Long, IOFSwitch> mySwitches = getMySwitches();
464
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800465 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800466 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
467 if (mySwitch == null)
468 continue;
469
470 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
471
472 //
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800473 // Push the Flow Entry into the switch
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800474 //
Pavlin Radoslavov6bfaea62013-12-03 14:55:57 -0800475 if (! pusher.add(mySwitch, flowEntry)) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800476 String logMsg = "Cannot install Flow Entry " +
477 flowEntry.flowEntryId() +
Pavlin Radoslavov6bfaea62013-12-03 14:55:57 -0800478 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800479 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700480 log.error(logMsg);
481 continue;
482 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800483 }
484 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700485
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800486 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800487 * Cleanup deleted Flow Entries from the datagrid.
488 *
489 * NOTE: We cleanup only the Flow Entries that are not for our switches.
490 * This is needed to handle the case a switch going down:
491 * It has no Master controller instance, hence no controller instance
492 * will cleanup its flow entries.
493 * This is sub-optimal: we need to elect a controller instance to handle
494 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800495 *
496 * @param modifiedFlowEntries the collection of modified Flow Entries.
497 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800498 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800499 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800500 if (modifiedFlowEntries.isEmpty())
501 return;
502
503 Map<Long, IOFSwitch> mySwitches = getMySwitches();
504
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800505 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800506 //
507 // Process only Flow Entries that should be deleted and have
508 // a valid Flow Entry ID.
509 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800510 if (! flowEntry.isValidFlowEntryId())
511 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800512 if (flowEntry.flowEntryUserState() !=
513 FlowEntryUserState.FE_USER_DELETE) {
514 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800515 }
516
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800517 //
518 // NOTE: The deletion of Flow Entries for my switches is handled
519 // elsewhere.
520 //
521 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
522 if (mySwitch != null)
523 continue;
524
525 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
526
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800527 //
528 // Write the Flow Entry to the Datagrid
529 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800530 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800531 }
532 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700533
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800534 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800535 * Class to implement writing to the database in a separate thread.
536 */
537 class FlowDatabaseWriter extends Thread {
538 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800539 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800540
541 /**
542 * Constructor.
543 *
544 * @param flowManager the Flow Manager to use.
545 * @param blockingQueue the blocking queue to use.
546 */
547 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800548 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800549 this.flowManager = flowManager;
550 this.blockingQueue = blockingQueue;
551 }
552
553 /**
554 * Run the thread.
555 */
556 @Override
557 public void run() {
558 //
559 // The main loop
560 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800561 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800562 try {
563 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800564 FlowPath flowPath = blockingQueue.take();
565 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800566 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800567 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800568 collection.clear();
569 }
570 } catch (Exception exception) {
571 log.debug("Exception writing to the Database: ", exception);
572 }
573 }
574 }
575
576 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800577 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800578 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800579 * NOTE: The complete Flow Paths are pushed only on the instance
580 * responsible for the first switch. This is to avoid database errors
581 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800582 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800583 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800584 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800585 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800586 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800587 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800588 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800589 // The FlowDatabaseWriter thread is responsible for the actual writing.
590 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800591 flowPathsToDatabaseQueue.addAll(modifiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800592 }
593
594 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800595 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800596 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800597 * NOTE: The complete Flow Paths are pushed only on the instance
598 * responsible for the first switch. This is to avoid database errors
599 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800600 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800601 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800602 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800603 private void writeModifiedFlowPathsToDatabase(
604 Collection<FlowPath> modifiedFlowPaths) {
605 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800606 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700607
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800608 FlowId dummyFlowId = new FlowId();
609
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800610 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700611
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800612 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800613 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800614 // Push the changes only on the instance responsible for the
615 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800616 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800617 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
618 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
619 if (mySrcSwitch == null)
620 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800621
622 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800623 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800624 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800625 boolean allValid = true;
626 for (FlowEntry flowEntry : flowPath.flowEntries()) {
627 if (flowEntry.flowEntryUserState() ==
628 FlowEntryUserState.FE_USER_DELETE) {
629 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700630 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800631 if (! flowEntry.isValidFlowEntryId()) {
632 allValid = false;
633 break;
634 }
635 }
636 if (! allValid)
637 continue;
638
639 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
640
641 //
642 // Write the Flow Path to the Network Map
643 //
644 try {
Pavlin Radoslavov67bf7622013-12-04 12:28:23 -0800645 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath,
646 dummyFlowId)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800647 String logMsg = "Cannot write to Network Map Flow Path " +
648 flowPath.flowId();
649 log.error(logMsg);
650 }
651 } catch (Exception e) {
652 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700653 }
654 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700655 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800656}