blob: b75b6036fce6fbd7161246c5e266c949ca163ad3 [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 Radoslavovff43b562013-11-20 17:13:48 -0800290 //
291 // TODO: In the notification-based implementation,
292 // deleteFlow() is implemented by using clearFlow()
293 //
294 return clearAllFlows();
295
296 /*
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800297 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700298 datagridService.notificationSendAllFlowsRemoved();
299 return true;
300 }
301 return false;
Pavlin Radoslavovff43b562013-11-20 17:13:48 -0800302 */
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000303 }
304
305 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800306 * Delete a previously added flow.
307 *
308 * @param flowId the Flow ID of the flow to delete.
309 * @return true on success, otherwise false.
310 */
311 @Override
312 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovff43b562013-11-20 17:13:48 -0800313 //
314 // TODO: In the notification-based implementation,
315 // deleteFlow() is implemented by using clearFlow()
316 //
317 return clearFlow(flowId);
318 /*
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800319 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700320 datagridService.notificationSendFlowRemoved(flowId);
321 return true;
322 }
323 return false;
Pavlin Radoslavovff43b562013-11-20 17:13:48 -0800324 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800325 }
326
327 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000328 * Clear the state for all previously added flows.
329 *
330 * @return true on success, otherwise false.
331 */
332 @Override
333 public boolean clearAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800334 if (FlowDatabaseOperation.clearAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700335 datagridService.notificationSendAllFlowsRemoved();
336 return true;
337 }
338 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000339 }
340
341 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700342 * Clear the state for a previously added flow.
343 *
344 * @param flowId the Flow ID of the flow to clear.
345 * @return true on success, otherwise false.
346 */
347 @Override
348 public boolean clearFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800349 if (FlowDatabaseOperation.clearFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700350 datagridService.notificationSendFlowRemoved(flowId);
351 return true;
352 }
353 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700354 }
355
356 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800357 * Get a previously added flow.
358 *
359 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800360 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800361 */
362 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800363 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800364 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700365 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800366
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700367 /**
368 * Get all installed flows by all installers.
369 *
370 * @return the Flow Paths if found, otherwise null.
371 */
372 @Override
373 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800374 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800375 }
376
377 /**
378 * Get all previously added flows by a specific installer for a given
379 * data path endpoints.
380 *
381 * @param installerId the Caller ID of the installer of the flow to get.
382 * @param dataPathEndpoints the data path endpoints of the flow to get.
383 * @return the Flow Paths if found, otherwise null.
384 */
385 @Override
386 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
387 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800388 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700389 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800390 }
391
392 /**
393 * Get all installed flows by all installers for given data path endpoints.
394 *
395 * @param dataPathEndpoints the data path endpoints of the flows to get.
396 * @return the Flow Paths if found, otherwise null.
397 */
398 @Override
399 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800400 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
401 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800402 }
403
404 /**
admin944ef4f2013-10-08 17:48:37 -0700405 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700406 *
admin944ef4f2013-10-08 17:48:37 -0700407 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700408 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700409 * @return the Flow Paths if found, otherwise null.
410 */
411 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700412 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
413 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800414 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700415 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700416 }
417
418 /**
admin944ef4f2013-10-08 17:48:37 -0700419 * Get all Flows information, without the associated Flow Entries.
420 *
421 * @return all Flows information, without the associated Flow Entries.
422 */
423 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800424 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700425 }
426
427 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700428 * Add and maintain a shortest-path flow.
429 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700430 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700431 *
432 * @param flowPath the Flow Path with the endpoints and the match
433 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700434 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700435 */
436 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700437 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700438 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000439 // Don't do the shortest path computation here.
440 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700441 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700442
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700443 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700444 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700445 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700446
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700447 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700448 }
449
450 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800451 * Get the collection of my switches.
452 *
453 * @return the collection of my switches.
454 */
455 public Map<Long, IOFSwitch> getMySwitches() {
456 return floodlightProvider.getSwitches();
457 }
458
459 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800460 * Get the network topology.
461 *
462 * @return the network topology.
463 */
464 public Topology getTopology() {
465 return flowEventHandler.getTopology();
466 }
467
468 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700469 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700470 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700471 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700472 * @param flowObj the flow path object for the flow entry to install.
473 * @param flowEntryObj the flow entry object to install.
474 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700475 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700476 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700477 IFlowEntry flowEntryObj) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800478 if (enableFlowPusher) {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800479 return pusher.add(mySwitch, flowObj, flowEntryObj);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800480 } else {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800481 return FlowSwitchOperation.installFlowEntry(
482 floodlightProvider.getOFMessageFactory(),
483 messageDamper, mySwitch, flowObj, flowEntryObj);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800484 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700485 }
486
487 /**
488 * Install a Flow Entry on a switch.
489 *
490 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700491 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700492 * @param flowEntry the flow entry to install.
493 * @return true on success, otherwise false.
494 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700495 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700496 FlowEntry flowEntry) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800497 if (enableFlowPusher) {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800498 return pusher.add(mySwitch, flowPath, flowEntry);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800499 } else {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800500 return FlowSwitchOperation.installFlowEntry(
501 floodlightProvider.getOFMessageFactory(),
502 messageDamper, mySwitch, flowPath, flowEntry);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800503 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700504 }
505
506 /**
507 * Remove a Flow Entry from a switch.
508 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700509 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700510 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700511 * @param flowEntry the flow entry to remove.
512 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700513 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700514 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700515 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700516 //
517 // The installFlowEntry() method implements both installation
518 // and removal of flow entries.
519 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700520 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700521 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700522
523 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800524 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700525 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800526 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700527 * are pushed.
528 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800529 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700530 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800531 public void pushModifiedFlowEntriesToSwitches(
532 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800533 if (modifiedFlowEntries.isEmpty())
534 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700535
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800536 Map<Long, IOFSwitch> mySwitches = getMySwitches();
537
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800538 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
539 FlowPath flowPath = flowPair.flowPath;
540 FlowEntry flowEntry = flowPair.flowEntry;
541
542 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
543 if (mySwitch == null)
544 continue;
545
546 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
547
548 //
549 // Install the Flow Entry into the switch
550 //
551 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
552 String logMsg = "Cannot install Flow Entry " +
553 flowEntry.flowEntryId() +
554 " from Flow Path " + flowPath.flowId() +
555 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700556 log.error(logMsg);
557 continue;
558 }
559
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800560 //
561 // NOTE: Here we assume that the switch has been
562 // successfully updated.
563 //
564 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
565 }
566 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700567
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800568 /**
569 * Push modified Flow Entries to the datagrid.
570 *
571 * @param modifiedFlowEntries the collection of modified Flow Entries.
572 */
573 public void pushModifiedFlowEntriesToDatagrid(
574 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800575 if (modifiedFlowEntries.isEmpty())
576 return;
577
578 Map<Long, IOFSwitch> mySwitches = getMySwitches();
579
580 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
581 FlowEntry flowEntry = flowPair.flowEntry;
582
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800583 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
584
585 //
586 // TODO: For now Flow Entries are removed by all instances,
587 // even if this Flow Entry is not for our switches.
588 //
589 // This is needed to handle the case a switch going down:
590 // it has no Master controller instance, hence no
591 // controller instance will cleanup its flow entries.
592 // This is sub-optimal: we need to elect a controller
593 // instance to handle the cleanup of such orphaned flow
594 // entries.
595 //
596 if (mySwitch == null) {
597 if (flowEntry.flowEntryUserState() !=
598 FlowEntryUserState.FE_USER_DELETE) {
599 continue;
600 }
601 if (! flowEntry.isValidFlowEntryId())
602 continue;
603 }
604
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800605 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800606 //
607 // Write the Flow Entry to the Datagrid
608 //
609 switch (flowEntry.flowEntryUserState()) {
610 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700611 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800612 break; // Install only flow entries for my switches
613 datagridService.notificationSendFlowEntryAdded(flowEntry);
614 break;
615 case FE_USER_MODIFY:
616 if (mySwitch == null)
617 break; // Install only flow entries for my switches
618 datagridService.notificationSendFlowEntryUpdated(flowEntry);
619 break;
620 case FE_USER_DELETE:
621 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
622 break;
623 }
624 }
625 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700626
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800627 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800628 * Class to implement writing to the database in a separate thread.
629 */
630 class FlowDatabaseWriter extends Thread {
631 private FlowManager flowManager;
632 private BlockingQueue<FlowPathEntryPair> blockingQueue;
633
634 /**
635 * Constructor.
636 *
637 * @param flowManager the Flow Manager to use.
638 * @param blockingQueue the blocking queue to use.
639 */
640 FlowDatabaseWriter(FlowManager flowManager,
641 BlockingQueue<FlowPathEntryPair> blockingQueue) {
642 this.flowManager = flowManager;
643 this.blockingQueue = blockingQueue;
644 }
645
646 /**
647 * Run the thread.
648 */
649 @Override
650 public void run() {
651 //
652 // The main loop
653 //
654 Collection<FlowPathEntryPair> collection =
655 new LinkedList<FlowPathEntryPair>();
656 try {
657 while (true) {
658 FlowPathEntryPair entryPair = blockingQueue.take();
659 collection.add(entryPair);
660 blockingQueue.drainTo(collection);
661 flowManager.writeModifiedFlowEntriesToDatabase(collection);
662 collection.clear();
663 }
664 } catch (Exception exception) {
665 log.debug("Exception writing to the Database: ", exception);
666 }
667 }
668 }
669
670 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800671 * Push Flow Entries to the Network MAP.
672 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800673 * NOTE: The Flow Entries are pushed only on the instance responsible
674 * for the first switch. This is to avoid database errors when multiple
675 * instances are writing Flow Entries for the same Flow Path.
676 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800677 * @param modifiedFlowEntries the collection of Flow Entries to push.
678 */
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800679 void pushModifiedFlowEntriesToDatabase(
680 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800681 //
682 // We only add the Flow Entries to the Database Queue.
683 // The FlowDatabaseWriter thread is responsible for the actual writing.
684 //
685 flowEntriesToDatabaseQueue.addAll(modifiedFlowEntries);
686 }
687
688 /**
689 * Write Flow Entries to the Network MAP.
690 *
691 * NOTE: The Flow Entries are written only on the instance responsible
692 * for the first switch. This is to avoid database errors when multiple
693 * instances are writing Flow Entries for the same Flow Path.
694 *
695 * @param modifiedFlowEntries the collection of Flow Entries to write.
696 */
697 private void writeModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800698 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800699 if (modifiedFlowEntries.isEmpty())
700 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700701
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800702 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700703
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800704 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
705 FlowPath flowPath = flowPair.flowPath;
706 FlowEntry flowEntry = flowPair.flowEntry;
707
708 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800709 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800710
711 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800712 // Push the changes only on the instance responsible for the
713 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800714 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800715 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
716 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
717 if (mySrcSwitch == null)
718 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800719
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800720 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800721 //
722 // Write the Flow Entry to the Network Map
723 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800724 // NOTE: We try a number of times, in case somehow some other
725 // instances are writing at the same time.
726 // Apparently, if other instances are writing at the same time
727 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800728 //
729 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700730 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800731 //
732 // Find the Flow Path in the Network MAP.
733 //
734 // NOTE: The Flow Path might not be found if the Flow was
735 // just removed by some other controller instance.
736 //
737 IFlowPath flowObj =
738 dbHandlerInner.searchFlowPath(flowEntry.flowId());
739 if (flowObj == null) {
740 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700741 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800742 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700743 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800744
745 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700746 switch (flowEntry.flowEntryUserState()) {
747 case FE_USER_ADD:
748 // FALLTHROUGH
749 case FE_USER_MODIFY:
750 if (addFlowEntry(flowObj, flowEntry) == null) {
751 String logMsg = "Cannot write to Network MAP Flow Entry " +
752 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800753 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700754 " on switch " + flowEntry.dpid();
755 log.error(logMsg);
756 }
757 break;
758 case FE_USER_DELETE:
759 if (deleteFlowEntry(flowObj, flowEntry) == false) {
760 String logMsg = "Cannot remove from Network MAP Flow Entry " +
761 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800762 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700763 " on switch " + flowEntry.dpid();
764 log.error(logMsg);
765 }
766 break;
767 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800768
769 // Commit to the database
770 dbHandlerInner.commit();
771 break; // Success
772
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700773 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800774 log.debug("Exception writing Flow Entry to Network MAP: ", e);
775 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800776 // Wait a bit (random value [1ms, 20ms] and try again
777 int delay = 1 + randomGenerator.nextInt() % 20;
778 try {
779 Thread.sleep(delay);
780 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700781 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700782 }
783 }
784 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700785 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800786}