blob: 8f72261bc11e6ab9549898b23c2e19252ae0d6ee [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;
Naoki Shiota1a37ca12013-11-18 10:55:23 -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 Radoslavov584bd112013-11-21 20:59:33 -080010import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080011import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080017import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080021import net.floodlightcontroller.restserver.IRestApiService;
Naoki Shiota1a37ca12013-11-18 10:55:23 -080022import net.floodlightcontroller.util.OFMessageDamper;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070023import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070024import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070025import net.onrc.onos.ofcontroller.core.INetMapStorage;
26import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
27import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070028import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070029import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080030import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070031import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070032import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033
Naoki Shiota1a37ca12013-11-18 10:55:23 -080034import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080035import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
admin944ef4f2013-10-08 17:48:37 -070038/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070039 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070040 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070041public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Naoki Shiota1a37ca12013-11-18 10:55:23 -080042 // flag to use FlowPusher instead of FlowSwitchOperation/MessageDamper
43 private final static boolean enableFlowPusher = false;
Pavlin Radoslavove0e48f72013-11-07 11:22:43 -080044
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080045 protected GraphDBOperation dbHandlerApi;
46 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080047
Jonathan Hart50a94982013-04-10 14:49:51 -070048 protected volatile IFloodlightProviderService floodlightProvider;
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 Radoslavov9a859022013-10-30 10:08:24 -070052 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080053
Brian O'Connor8c166a72013-11-14 18:41:48 -080054 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080055
Naoki Shiota1a37ca12013-11-18 10:55:23 -080056 protected OFMessageDamper messageDamper;
57
58 //
59 // TODO: Values copied from elsewhere (class LearningSwitch).
60 // The local copy should go away!
61 //
62 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
63 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080064
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000065 // Flow Entry ID generation state
66 private static Random randomGenerator = new Random();
67 private static int nextFlowEntryIdPrefix = 0;
68 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000069
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070071 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080073 // The queue to write Flow Entries to the database
74 private BlockingQueue<FlowPathEntryPair> flowEntriesToDatabaseQueue =
75 new LinkedBlockingQueue<FlowPathEntryPair>();
76 FlowDatabaseWriter flowDatabaseWriter;
77
admin944ef4f2013-10-08 17:48:37 -070078 /**
79 * Initialize the Flow Manager.
80 *
81 * @param conf the Graph Database configuration string.
82 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080083 @Override
84 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080085 dbHandlerApi = new GraphDBOperation(conf);
86 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080087 }
88
admin944ef4f2013-10-08 17:48:37 -070089 /**
90 * Shutdown the Flow Manager operation.
91 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080092 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070093 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080094 }
95
admin944ef4f2013-10-08 17:48:37 -070096 /**
97 * Shutdown the Flow Manager operation.
98 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080099 @Override
100 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700101 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800102 dbHandlerApi.close();
103 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800104 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800105
admin944ef4f2013-10-08 17:48:37 -0700106 /**
107 * Get the collection of offered module services.
108 *
109 * @return the collection of offered module services.
110 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800111 @Override
112 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
113 Collection<Class<? extends IFloodlightService>> l =
114 new ArrayList<Class<? extends IFloodlightService>>();
115 l.add(IFlowService.class);
116 return l;
117 }
118
admin944ef4f2013-10-08 17:48:37 -0700119 /**
120 * Get the collection of implemented services.
121 *
122 * @return the collection of implemented services.
123 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800124 @Override
125 public Map<Class<? extends IFloodlightService>, IFloodlightService>
126 getServiceImpls() {
127 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700128 IFloodlightService> m =
129 new HashMap<Class<? extends IFloodlightService>,
130 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800131 m.put(IFlowService.class, this);
132 return m;
133 }
134
admin944ef4f2013-10-08 17:48:37 -0700135 /**
136 * Get the collection of modules this module depends on.
137 *
138 * @return the collection of modules this module depends on.
139 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800140 @Override
141 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700142 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800143 Collection<Class<? extends IFloodlightService>> l =
144 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800145 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700146 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700147 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800148 l.add(IRestApiService.class);
149 return l;
150 }
151
admin944ef4f2013-10-08 17:48:37 -0700152 /**
153 * Initialize the module.
154 *
155 * @param context the module context to use for the initialization.
156 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800157 @Override
158 public void init(FloodlightModuleContext context)
159 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700160 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800161 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700162 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800163 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700164
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800165 if (enableFlowPusher) {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800166 pusher = context.getServiceImpl(IFlowPusherService.class);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800167 } else {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800168 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800169 EnumSet.of(OFType.FLOW_MOD),
170 OFMESSAGE_DAMPER_TIMEOUT);
171 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800172
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700173 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800174 }
175
admin944ef4f2013-10-08 17:48:37 -0700176 /**
177 * Get the next Flow Entry ID to use.
178 *
179 * @return the next Flow Entry ID to use.
180 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800181 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700182 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000183 //
184 // Generate the next Flow Entry ID.
185 // NOTE: For now, the higher 32 bits are random, and
186 // the lower 32 bits are sequential.
187 // In the future, we need a better allocation mechanism.
188 //
189 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
190 nextFlowEntryIdPrefix = randomGenerator.nextInt();
191 nextFlowEntryIdSuffix = 0;
192 } else {
193 nextFlowEntryIdSuffix++;
194 }
195 long result = (long)nextFlowEntryIdPrefix << 32;
196 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
197 return result;
198 }
199
admin944ef4f2013-10-08 17:48:37 -0700200 /**
201 * Startup module operation.
202 *
203 * @param context the module context to use for the startup.
204 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800205 @Override
206 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700207 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700208
admin944ef4f2013-10-08 17:48:37 -0700209 // Initialize the Flow Entry ID generator
210 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800211
212 //
213 // The thread to write to the database
214 //
215 flowDatabaseWriter = new FlowDatabaseWriter(this,
216 flowEntriesToDatabaseQueue);
217 flowDatabaseWriter.start();
218
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700219 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800220 // The Flow Event Handler thread:
221 // - create
222 // - register with the Datagrid Service
223 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700224 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700225 flowEventHandler = new FlowEventHandler(this, datagridService);
226 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700227 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800228 }
229
230 /**
231 * Add a flow.
232 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800233 * @param flowPath the Flow Path to install.
234 * @param flowId the return-by-reference Flow ID as assigned internally.
235 * @return true on success, otherwise false.
236 */
237 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700238 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700239 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700240 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700241 // in case the application didn't do it.
242 //
243 for (FlowEntry flowEntry : flowPath.flowEntries()) {
244 if (flowEntry.flowEntrySwitchState() ==
245 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
246 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
247 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700248 if (! flowEntry.isValidFlowId())
249 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700250 }
251
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800252 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700253 datagridService.notificationSendFlowAdded(flowPath);
254 return true;
255 }
256 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800257 }
258
259 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700260 * Add a flow entry to the Network MAP.
261 *
262 * @param flowObj the corresponding Flow Path object for the Flow Entry.
263 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700264 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700265 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700266 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800267 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
268 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700269 }
270
271 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700272 * Delete a flow entry from the Network MAP.
273 *
274 * @param flowObj the corresponding Flow Path object for the Flow Entry.
275 * @param flowEntry the Flow Entry to delete.
276 * @return true on success, otherwise false.
277 */
278 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800279 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
280 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800281 }
282
283 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000284 * Delete all previously added flows.
285 *
286 * @return true on success, otherwise false.
287 */
288 @Override
289 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800290 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700291 datagridService.notificationSendAllFlowsRemoved();
292 return true;
293 }
294 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000295 }
296
297 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800298 * Delete a previously added flow.
299 *
300 * @param flowId the Flow ID of the flow to delete.
301 * @return true on success, otherwise false.
302 */
303 @Override
304 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800305 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700306 datagridService.notificationSendFlowRemoved(flowId);
307 return true;
308 }
309 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700310 }
311
312 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800313 * Get a previously added flow.
314 *
315 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800316 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800317 */
318 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800319 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800320 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700321 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800322
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700323 /**
324 * Get all installed flows by all installers.
325 *
326 * @return the Flow Paths if found, otherwise null.
327 */
328 @Override
329 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800330 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800331 }
332
333 /**
334 * Get all previously added flows by a specific installer for a given
335 * data path endpoints.
336 *
337 * @param installerId the Caller ID of the installer of the flow to get.
338 * @param dataPathEndpoints the data path endpoints of the flow to get.
339 * @return the Flow Paths if found, otherwise null.
340 */
341 @Override
342 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
343 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800344 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700345 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800346 }
347
348 /**
349 * Get all installed flows by all installers for given data path endpoints.
350 *
351 * @param dataPathEndpoints the data path endpoints of the flows to get.
352 * @return the Flow Paths if found, otherwise null.
353 */
354 @Override
355 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800356 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
357 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800358 }
359
360 /**
admin944ef4f2013-10-08 17:48:37 -0700361 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700362 *
admin944ef4f2013-10-08 17:48:37 -0700363 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700364 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700365 * @return the Flow Paths if found, otherwise null.
366 */
367 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800368 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
369 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800370 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700371 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700372 }
373
374 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700375 * Add and maintain a shortest-path flow.
376 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700377 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700378 *
379 * @param flowPath the Flow Path with the endpoints and the match
380 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700381 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700382 */
383 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700384 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700385 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000386 // Don't do the shortest path computation here.
387 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700388 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700389
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700390 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700391 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700392 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700393
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700394 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700395 }
396
397 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800398 * Get the collection of my switches.
399 *
400 * @return the collection of my switches.
401 */
402 public Map<Long, IOFSwitch> getMySwitches() {
403 return floodlightProvider.getSwitches();
404 }
405
406 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800407 * Get the network topology.
408 *
409 * @return the network topology.
410 */
411 public Topology getTopology() {
412 return flowEventHandler.getTopology();
413 }
414
415 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700416 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700417 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700418 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700419 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700420 * @param flowEntry the flow entry to install.
421 * @return true on success, otherwise false.
422 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700423 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700424 FlowEntry flowEntry) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800425 if (enableFlowPusher) {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800426 return pusher.add(mySwitch, flowPath, flowEntry);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800427 } else {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800428 return FlowSwitchOperation.installFlowEntry(
429 floodlightProvider.getOFMessageFactory(),
430 messageDamper, mySwitch, flowPath, flowEntry);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800431 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700432 }
433
434 /**
435 * Remove a Flow Entry from a switch.
436 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700437 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700438 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700439 * @param flowEntry the flow entry to remove.
440 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700441 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700442 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700443 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700444 //
445 // The installFlowEntry() method implements both installation
446 // and removal of flow entries.
447 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700448 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700449 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700450
451 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800452 * Inform the Flow Manager that a Flow Entry on switch expired.
453 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800454 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800455 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
456 */
Brian O'Connor4f0b60c2013-11-26 15:00:04 -0800457 public void flowEntryOnSwitchExpired(IOFSwitch sw, FlowEntryId flowEntryId) {
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800458 // TODO: Not implemented yet
459 }
460
461 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800462 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700463 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800464 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700465 * are pushed.
466 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800467 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700468 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800469 public void pushModifiedFlowEntriesToSwitches(
470 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800471 if (modifiedFlowEntries.isEmpty())
472 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700473
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800474 Map<Long, IOFSwitch> mySwitches = getMySwitches();
475
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800476 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
477 FlowPath flowPath = flowPair.flowPath;
478 FlowEntry flowEntry = flowPair.flowEntry;
479
480 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
481 if (mySwitch == null)
482 continue;
483
484 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
485
486 //
487 // Install the Flow Entry into the switch
488 //
489 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
490 String logMsg = "Cannot install Flow Entry " +
491 flowEntry.flowEntryId() +
492 " from Flow Path " + flowPath.flowId() +
493 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700494 log.error(logMsg);
495 continue;
496 }
497
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800498 //
499 // NOTE: Here we assume that the switch has been
500 // successfully updated.
501 //
502 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
503 }
504 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700505
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800506 /**
507 * Push modified Flow Entries to the datagrid.
508 *
509 * @param modifiedFlowEntries the collection of modified Flow Entries.
510 */
511 public void pushModifiedFlowEntriesToDatagrid(
512 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800513 if (modifiedFlowEntries.isEmpty())
514 return;
515
516 Map<Long, IOFSwitch> mySwitches = getMySwitches();
517
518 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
519 FlowEntry flowEntry = flowPair.flowEntry;
520
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800521 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
522
523 //
524 // TODO: For now Flow Entries are removed by all instances,
525 // even if this Flow Entry is not for our switches.
526 //
527 // This is needed to handle the case a switch going down:
528 // it has no Master controller instance, hence no
529 // controller instance will cleanup its flow entries.
530 // This is sub-optimal: we need to elect a controller
531 // instance to handle the cleanup of such orphaned flow
532 // entries.
533 //
534 if (mySwitch == null) {
535 if (flowEntry.flowEntryUserState() !=
536 FlowEntryUserState.FE_USER_DELETE) {
537 continue;
538 }
539 if (! flowEntry.isValidFlowEntryId())
540 continue;
541 }
542
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800543 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800544 //
545 // Write the Flow Entry to the Datagrid
546 //
547 switch (flowEntry.flowEntryUserState()) {
548 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700549 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800550 break; // Install only flow entries for my switches
551 datagridService.notificationSendFlowEntryAdded(flowEntry);
552 break;
553 case FE_USER_MODIFY:
554 if (mySwitch == null)
555 break; // Install only flow entries for my switches
556 datagridService.notificationSendFlowEntryUpdated(flowEntry);
557 break;
558 case FE_USER_DELETE:
559 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
560 break;
561 }
562 }
563 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700564
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800565 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800566 * Class to implement writing to the database in a separate thread.
567 */
568 class FlowDatabaseWriter extends Thread {
569 private FlowManager flowManager;
570 private BlockingQueue<FlowPathEntryPair> blockingQueue;
571
572 /**
573 * Constructor.
574 *
575 * @param flowManager the Flow Manager to use.
576 * @param blockingQueue the blocking queue to use.
577 */
578 FlowDatabaseWriter(FlowManager flowManager,
579 BlockingQueue<FlowPathEntryPair> blockingQueue) {
580 this.flowManager = flowManager;
581 this.blockingQueue = blockingQueue;
582 }
583
584 /**
585 * Run the thread.
586 */
587 @Override
588 public void run() {
589 //
590 // The main loop
591 //
592 Collection<FlowPathEntryPair> collection =
593 new LinkedList<FlowPathEntryPair>();
594 try {
595 while (true) {
596 FlowPathEntryPair entryPair = blockingQueue.take();
597 collection.add(entryPair);
598 blockingQueue.drainTo(collection);
599 flowManager.writeModifiedFlowEntriesToDatabase(collection);
600 collection.clear();
601 }
602 } catch (Exception exception) {
603 log.debug("Exception writing to the Database: ", exception);
604 }
605 }
606 }
607
608 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800609 * Push Flow Entries to the Network MAP.
610 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800611 * NOTE: The Flow Entries are pushed only on the instance responsible
612 * for the first switch. This is to avoid database errors when multiple
613 * instances are writing Flow Entries for the same Flow Path.
614 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800615 * @param modifiedFlowEntries the collection of Flow Entries to push.
616 */
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800617 void pushModifiedFlowEntriesToDatabase(
618 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800619 //
620 // We only add the Flow Entries to the Database Queue.
621 // The FlowDatabaseWriter thread is responsible for the actual writing.
622 //
623 flowEntriesToDatabaseQueue.addAll(modifiedFlowEntries);
624 }
625
626 /**
627 * Write Flow Entries to the Network MAP.
628 *
629 * NOTE: The Flow Entries are written only on the instance responsible
630 * for the first switch. This is to avoid database errors when multiple
631 * instances are writing Flow Entries for the same Flow Path.
632 *
633 * @param modifiedFlowEntries the collection of Flow Entries to write.
634 */
635 private void writeModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800636 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800637 if (modifiedFlowEntries.isEmpty())
638 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700639
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800640 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700641
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800642 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
643 FlowPath flowPath = flowPair.flowPath;
644 FlowEntry flowEntry = flowPair.flowEntry;
645
646 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800647 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800648
649 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800650 // Push the changes only on the instance responsible for the
651 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800652 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800653 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
654 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
655 if (mySrcSwitch == null)
656 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800657
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800658 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800659 //
660 // Write the Flow Entry to the Network Map
661 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800662 // NOTE: We try a number of times, in case somehow some other
663 // instances are writing at the same time.
664 // Apparently, if other instances are writing at the same time
665 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800666 //
667 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700668 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800669 //
670 // Find the Flow Path in the Network MAP.
671 //
672 // NOTE: The Flow Path might not be found if the Flow was
673 // just removed by some other controller instance.
674 //
675 IFlowPath flowObj =
676 dbHandlerInner.searchFlowPath(flowEntry.flowId());
677 if (flowObj == null) {
678 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700679 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800680 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700681 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800682
683 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700684 switch (flowEntry.flowEntryUserState()) {
685 case FE_USER_ADD:
686 // FALLTHROUGH
687 case FE_USER_MODIFY:
688 if (addFlowEntry(flowObj, flowEntry) == null) {
689 String logMsg = "Cannot write to Network MAP Flow Entry " +
690 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800691 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700692 " on switch " + flowEntry.dpid();
693 log.error(logMsg);
694 }
695 break;
696 case FE_USER_DELETE:
697 if (deleteFlowEntry(flowObj, flowEntry) == false) {
698 String logMsg = "Cannot remove from Network MAP Flow Entry " +
699 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800700 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700701 " on switch " + flowEntry.dpid();
702 log.error(logMsg);
703 }
704 break;
705 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800706
707 // Commit to the database
708 dbHandlerInner.commit();
709 break; // Success
710
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700711 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800712 log.debug("Exception writing Flow Entry to Network MAP: ", e);
713 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800714 // Wait a bit (random value [1ms, 20ms] and try again
715 int delay = 1 + randomGenerator.nextInt() % 20;
716 try {
717 Thread.sleep(delay);
718 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700719 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700720 }
721 }
722 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700723 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800724}