blob: 68450c2b513b947278afff14d412fa80e00a2069 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
3import java.util.ArrayList;
4import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08005import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00007import java.util.LinkedList;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00009import java.util.Random;
Pavlin 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;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.util.OFMessageDamper;
yoshi2fd4c7e2013-11-22 15:47:55 -080023import net.onrc.onos.graph.DBOperation;
24import net.onrc.onos.graph.GraphDBManager;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070025import net.onrc.onos.datagrid.IDatagridService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070026import net.onrc.onos.ofcontroller.core.INetMapStorage;
27import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
28import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070029import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070030import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080031import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070032import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070033import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080034
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
admin944ef4f2013-10-08 17:48:37 -070039/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070040 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070041 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070042public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Naoki Shiota1a37ca12013-11-18 10:55:23 -080043 // flag to use FlowPusher instead of FlowSwitchOperation/MessageDamper
44 private final static boolean enableFlowPusher = false;
yoshitomob292c622013-11-23 14:35:58 -080045 protected DBOperation dbHandlerApi;
46 protected DBOperation 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
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056 protected OFMessageDamper messageDamper;
Naoki Shiota1a37ca12013-11-18 10:55:23 -080057
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070058 //
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 Radoslavov01391c92013-03-14 17:13:21 -070069
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;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077
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
yoshi2fd4c7e2013-11-22 15:47:55 -080084 public void init(final String dbStore, final String conf) {
yoshitomob292c622013-11-23 14:35:58 -080085 dbHandlerApi = GraphDBManager.getDBOperation(dbStore, conf);
86 dbHandlerInner = GraphDBManager.getDBOperation(dbStore, conf);
87
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080088 }
89
admin944ef4f2013-10-08 17:48:37 -070090 /**
91 * Shutdown the Flow Manager operation.
92 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070094 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080095 }
96
admin944ef4f2013-10-08 17:48:37 -070097 /**
98 * Shutdown the Flow Manager operation.
99 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800100 @Override
101 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700102 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800103 dbHandlerApi.close();
104 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800105 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800106
admin944ef4f2013-10-08 17:48:37 -0700107 /**
108 * Get the collection of offered module services.
109 *
110 * @return the collection of offered module services.
111 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800112 @Override
113 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
114 Collection<Class<? extends IFloodlightService>> l =
115 new ArrayList<Class<? extends IFloodlightService>>();
116 l.add(IFlowService.class);
117 return l;
118 }
119
admin944ef4f2013-10-08 17:48:37 -0700120 /**
121 * Get the collection of implemented services.
122 *
123 * @return the collection of implemented services.
124 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800125 @Override
126 public Map<Class<? extends IFloodlightService>, IFloodlightService>
127 getServiceImpls() {
128 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700129 IFloodlightService> m =
130 new HashMap<Class<? extends IFloodlightService>,
131 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800132 m.put(IFlowService.class, this);
133 return m;
134 }
135
admin944ef4f2013-10-08 17:48:37 -0700136 /**
137 * Get the collection of modules this module depends on.
138 *
139 * @return the collection of modules this module depends on.
140 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800141 @Override
142 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700143 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800144 Collection<Class<? extends IFloodlightService>> l =
145 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800146 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700147 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700148 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800149 l.add(IRestApiService.class);
150 return l;
151 }
152
admin944ef4f2013-10-08 17:48:37 -0700153 /**
154 * Initialize the module.
155 *
156 * @param context the module context to use for the initialization.
157 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800158 @Override
159 public void init(FloodlightModuleContext context)
160 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700161 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800162 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700163 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800164 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700165
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800166 if (enableFlowPusher) {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800167 pusher = context.getServiceImpl(IFlowPusherService.class);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800168 } else {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800169 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800170 EnumSet.of(OFType.FLOW_MOD),
171 OFMESSAGE_DAMPER_TIMEOUT);
172 }
Brian O'Connor8c166a72013-11-14 18:41:48 -0800173
yoshi0fee3de2013-11-23 09:13:37 -0800174 this.init("","");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800175 }
176
admin944ef4f2013-10-08 17:48:37 -0700177 /**
178 * Get the next Flow Entry ID to use.
179 *
180 * @return the next Flow Entry ID to use.
181 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800182 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700183 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000184 //
185 // Generate the next Flow Entry ID.
186 // NOTE: For now, the higher 32 bits are random, and
187 // the lower 32 bits are sequential.
188 // In the future, we need a better allocation mechanism.
189 //
190 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
191 nextFlowEntryIdPrefix = randomGenerator.nextInt();
192 nextFlowEntryIdSuffix = 0;
193 } else {
194 nextFlowEntryIdSuffix++;
195 }
196 long result = (long)nextFlowEntryIdPrefix << 32;
197 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
198 return result;
199 }
200
admin944ef4f2013-10-08 17:48:37 -0700201 /**
202 * Startup module operation.
203 *
204 * @param context the module context to use for the startup.
205 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800206 @Override
207 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700208 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700209
admin944ef4f2013-10-08 17:48:37 -0700210 // Initialize the Flow Entry ID generator
211 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800212
213 //
214 // The thread to write to the database
215 //
216 flowDatabaseWriter = new FlowDatabaseWriter(this,
217 flowEntriesToDatabaseQueue);
218 flowDatabaseWriter.start();
219
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700220 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800221 // The Flow Event Handler thread:
222 // - create
223 // - register with the Datagrid Service
224 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700225 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700226 flowEventHandler = new FlowEventHandler(this, datagridService);
227 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700228 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800229 }
230
231 /**
232 * Add a flow.
233 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800234 * @param flowPath the Flow Path to install.
235 * @param flowId the return-by-reference Flow ID as assigned internally.
236 * @return true on success, otherwise false.
237 */
238 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700239 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700240 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700241 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700242 // in case the application didn't do it.
243 //
244 for (FlowEntry flowEntry : flowPath.flowEntries()) {
245 if (flowEntry.flowEntrySwitchState() ==
246 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
247 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800248 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700249 if (! flowEntry.isValidFlowId())
250 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700251 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800252
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800253 if (FlowDatabaseOperation.addFlow(this, dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700254 datagridService.notificationSendFlowAdded(flowPath);
255 return true;
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700256 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700257 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800258 }
259
260 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700261 * Add a flow entry to the Network MAP.
262 *
263 * @param flowObj the corresponding Flow Path object for the Flow Entry.
264 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700265 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700266 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700267 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800268 return FlowDatabaseOperation.addFlowEntry(this, dbHandlerInner,
269 flowObj, flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700270 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800271
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700272 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700273 * Delete a flow entry from the Network MAP.
274 *
275 * @param flowObj the corresponding Flow Path object for the Flow Entry.
276 * @param flowEntry the Flow Entry to delete.
277 * @return true on success, otherwise false.
278 */
279 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800280 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
281 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800282 }
283
284 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000285 * Delete all previously added flows.
286 *
287 * @return true on success, otherwise false.
288 */
289 @Override
290 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800291 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700292 datagridService.notificationSendAllFlowsRemoved();
293 return true;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000294 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700295 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000296 }
297
298 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800299 * Delete a previously added flow.
300 *
301 * @param flowId the Flow ID of the flow to delete.
302 * @return true on success, otherwise false.
303 */
304 @Override
305 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800306 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700307 datagridService.notificationSendFlowRemoved(flowId);
308 return true;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700309 }
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700310 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700311 }
312
313 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800314 * Get a previously added flow.
315 *
316 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800317 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800318 */
319 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800320 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800321 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700322 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800323
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700324 /**
325 * Get all installed flows by all installers.
326 *
327 * @return the Flow Paths if found, otherwise null.
328 */
329 @Override
330 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800331 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800332 }
333
334 /**
335 * Get all previously added flows by a specific installer for a given
336 * data path endpoints.
337 *
338 * @param installerId the Caller ID of the installer of the flow to get.
339 * @param dataPathEndpoints the data path endpoints of the flow to get.
340 * @return the Flow Paths if found, otherwise null.
341 */
342 @Override
343 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
344 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800345 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700346 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800347 }
348
349 /**
350 * Get all installed flows by all installers for given data path endpoints.
351 *
352 * @param dataPathEndpoints the data path endpoints of the flows to get.
353 * @return the Flow Paths if found, otherwise null.
354 */
355 @Override
356 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800357 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
358 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800359 }
360
361 /**
admin944ef4f2013-10-08 17:48:37 -0700362 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700363 *
admin944ef4f2013-10-08 17:48:37 -0700364 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700365 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700366 * @return the Flow Paths if found, otherwise null.
367 */
368 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700369 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
370 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800371 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700372 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700373 }
374
375 /**
admin944ef4f2013-10-08 17:48:37 -0700376 * Get all Flows information, without the associated Flow Entries.
377 *
378 * @return all Flows information, without the associated Flow Entries.
379 */
380 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800381 return FlowDatabaseOperation.getAllFlowsWithoutFlowEntries(dbHandlerApi);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -0700382 }
383
384 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700385 * Add and maintain a shortest-path flow.
386 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700387 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700388 *
389 * @param flowPath the Flow Path with the endpoints and the match
390 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700391 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700392 */
393 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700394 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700395 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000396 // Don't do the shortest path computation here.
397 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700398 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700399
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700400 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700401 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700402 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700403
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700404 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700405 }
406
407 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800408 * Get the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700409 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800410 * @return the collection of my switches.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700411 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800412 public Map<Long, IOFSwitch> getMySwitches() {
413 return floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700414 }
415
416 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800417 * Get the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700418 *
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800419 * @return the network topology.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700420 */
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800421 public Topology getTopology() {
422 return flowEventHandler.getTopology();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700423 }
424
425 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700426 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700427 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700428 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700429 * @param flowObj the flow path object for the flow entry to install.
430 * @param flowEntryObj the flow entry object to install.
431 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700432 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700433 private boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700434 IFlowEntry flowEntryObj) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800435 if (enableFlowPusher) {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800436 return pusher.add(mySwitch, flowObj, flowEntryObj);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800437 } else {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800438 return FlowSwitchOperation.installFlowEntry(
439 floodlightProvider.getOFMessageFactory(),
440 messageDamper, mySwitch, flowObj, flowEntryObj);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800441 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700442 }
443
444 /**
445 * Install a Flow Entry on a switch.
446 *
447 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700448 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700449 * @param flowEntry the flow entry to install.
450 * @return true on success, otherwise false.
451 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700452 private boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700453 FlowEntry flowEntry) {
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800454 if (enableFlowPusher) {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800455 return pusher.add(mySwitch, flowPath, flowEntry);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800456 } else {
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800457 return FlowSwitchOperation.installFlowEntry(
458 floodlightProvider.getOFMessageFactory(),
459 messageDamper, mySwitch, flowPath, flowEntry);
Naoki Shiota1a37ca12013-11-18 10:55:23 -0800460 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700461 }
462
463 /**
464 * Remove a Flow Entry from a switch.
465 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -0700466 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700467 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700468 * @param flowEntry the flow entry to remove.
469 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700470 */
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700471 private boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700472 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700473 //
474 // The installFlowEntry() method implements both installation
475 // and removal of flow entries.
476 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700477 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700478 }
479
480 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800481 * Push modified Flow Entries to switches.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700482 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800483 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700484 * are pushed.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700485 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800486 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700487 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800488 public void pushModifiedFlowEntriesToSwitches(
489 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800490 if (modifiedFlowEntries.isEmpty())
491 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700492
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800493 Map<Long, IOFSwitch> mySwitches = getMySwitches();
494
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800495 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
496 FlowPath flowPath = flowPair.flowPath;
497 FlowEntry flowEntry = flowPair.flowEntry;
498
499 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
500 if (mySwitch == null)
501 continue;
502
503 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
504
505 //
506 // Install the Flow Entry into the switch
507 //
508 if (! installFlowEntry(mySwitch, flowPath, flowEntry)) {
509 String logMsg = "Cannot install Flow Entry " +
510 flowEntry.flowEntryId() +
511 " from Flow Path " + flowPath.flowId() +
512 " on switch " + flowEntry.dpid();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700513 log.error(logMsg);
514 continue;
515 }
516
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800517 //
518 // NOTE: Here we assume that the switch has been
519 // successfully updated.
520 //
521 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
522 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700523 }
524
525 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800526 * Push modified Flow Entries to the datagrid.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700527 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800528 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700529 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800530 public void pushModifiedFlowEntriesToDatagrid(
531 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800532 if (modifiedFlowEntries.isEmpty())
533 return;
534
535 Map<Long, IOFSwitch> mySwitches = getMySwitches();
536
537 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
538 FlowEntry flowEntry = flowPair.flowEntry;
539
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800540 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
541
542 //
543 // TODO: For now Flow Entries are removed by all instances,
544 // even if this Flow Entry is not for our switches.
545 //
546 // This is needed to handle the case a switch going down:
547 // it has no Master controller instance, hence no
548 // controller instance will cleanup its flow entries.
549 // This is sub-optimal: we need to elect a controller
550 // instance to handle the cleanup of such orphaned flow
551 // entries.
552 //
553 if (mySwitch == null) {
554 if (flowEntry.flowEntryUserState() !=
555 FlowEntryUserState.FE_USER_DELETE) {
556 continue;
557 }
558 if (! flowEntry.isValidFlowEntryId())
559 continue;
560 }
561
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800562 log.debug("Pushing Flow Entry To Datagrid: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800563 //
564 // Write the Flow Entry to the Datagrid
565 //
566 switch (flowEntry.flowEntryUserState()) {
567 case FE_USER_ADD:
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700568 if (mySwitch == null)
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800569 break; // Install only flow entries for my switches
570 datagridService.notificationSendFlowEntryAdded(flowEntry);
571 break;
572 case FE_USER_MODIFY:
573 if (mySwitch == null)
574 break; // Install only flow entries for my switches
575 datagridService.notificationSendFlowEntryUpdated(flowEntry);
576 break;
577 case FE_USER_DELETE:
578 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
579 break;
580 }
581 }
582 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700583
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800584 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800585 * Class to implement writing to the database in a separate thread.
586 */
587 class FlowDatabaseWriter extends Thread {
588 private FlowManager flowManager;
589 private BlockingQueue<FlowPathEntryPair> blockingQueue;
590
591 /**
592 * Constructor.
593 *
594 * @param flowManager the Flow Manager to use.
595 * @param blockingQueue the blocking queue to use.
596 */
597 FlowDatabaseWriter(FlowManager flowManager,
598 BlockingQueue<FlowPathEntryPair> blockingQueue) {
599 this.flowManager = flowManager;
600 this.blockingQueue = blockingQueue;
601 }
602
603 /**
604 * Run the thread.
605 */
606 @Override
607 public void run() {
608 //
609 // The main loop
610 //
611 Collection<FlowPathEntryPair> collection =
612 new LinkedList<FlowPathEntryPair>();
613 try {
614 while (true) {
615 FlowPathEntryPair entryPair = blockingQueue.take();
616 collection.add(entryPair);
617 blockingQueue.drainTo(collection);
618 flowManager.writeModifiedFlowEntriesToDatabase(collection);
619 collection.clear();
620 }
621 } catch (Exception exception) {
622 log.debug("Exception writing to the Database: ", exception);
623 }
624 }
625 }
626
627 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800628 * Push Flow Entries to the Network MAP.
629 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800630 * NOTE: The Flow Entries are pushed only on the instance responsible
631 * for the first switch. This is to avoid database errors when multiple
632 * instances are writing Flow Entries for the same Flow Path.
633 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800634 * @param modifiedFlowEntries the collection of Flow Entries to push.
635 */
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800636 void pushModifiedFlowEntriesToDatabase(
637 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700638 //
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800639 // We only add the Flow Entries to the Database Queue.
640 // The FlowDatabaseWriter thread is responsible for the actual writing.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -0700641 //
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800642 flowEntriesToDatabaseQueue.addAll(modifiedFlowEntries);
643 }
644
645 /**
646 * Write Flow Entries to the Network MAP.
647 *
648 * NOTE: The Flow Entries are written only on the instance responsible
649 * for the first switch. This is to avoid database errors when multiple
650 * instances are writing Flow Entries for the same Flow Path.
651 *
652 * @param modifiedFlowEntries the collection of Flow Entries to write.
653 */
654 private void writeModifiedFlowEntriesToDatabase(
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800655 Collection<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800656 if (modifiedFlowEntries.isEmpty())
657 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700658
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800659 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700660
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800661 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
662 FlowPath flowPath = flowPair.flowPath;
663 FlowEntry flowEntry = flowPair.flowEntry;
664
665 if (! flowEntry.isValidFlowEntryId())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800666 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800667
668 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800669 // Push the changes only on the instance responsible for the
670 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800671 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800672 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
673 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
674 if (mySrcSwitch == null)
675 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800676
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800677 log.debug("Pushing Flow Entry To Database: {}", flowEntry.toString());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800678 //
679 // Write the Flow Entry to the Network Map
680 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800681 // NOTE: We try a number of times, in case somehow some other
682 // instances are writing at the same time.
683 // Apparently, if other instances are writing at the same time
684 // this will trigger an error.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800685 //
686 for (int i = 0; i < 6; i++) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700687 try {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800688 //
689 // Find the Flow Path in the Network MAP.
690 //
691 // NOTE: The Flow Path might not be found if the Flow was
692 // just removed by some other controller instance.
693 //
694 IFlowPath flowObj =
695 dbHandlerInner.searchFlowPath(flowEntry.flowId());
696 if (flowObj == null) {
697 String logMsg = "Cannot find Network MAP entry for Flow Path " + flowEntry.flowId();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700698 log.error(logMsg);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800699 break;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700700 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800701
702 // Write the Flow Entry
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700703 switch (flowEntry.flowEntryUserState()) {
704 case FE_USER_ADD:
705 // FALLTHROUGH
706 case FE_USER_MODIFY:
707 if (addFlowEntry(flowObj, flowEntry) == null) {
708 String logMsg = "Cannot write to Network MAP Flow Entry " +
709 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800710 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700711 " on switch " + flowEntry.dpid();
712 log.error(logMsg);
713 }
714 break;
715 case FE_USER_DELETE:
716 if (deleteFlowEntry(flowObj, flowEntry) == false) {
717 String logMsg = "Cannot remove from Network MAP Flow Entry " +
718 flowEntry.flowEntryId() +
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800719 " from Flow Path " + flowEntry.flowId() +
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700720 " on switch " + flowEntry.dpid();
721 log.error(logMsg);
722 }
723 break;
724 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800725
726 // Commit to the database
727 dbHandlerInner.commit();
728 break; // Success
729
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700730 } catch (Exception e) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800731 log.debug("Exception writing Flow Entry to Network MAP: ", e);
732 dbHandlerInner.rollback();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800733 // Wait a bit (random value [1ms, 20ms] and try again
734 int delay = 1 + randomGenerator.nextInt() % 20;
735 try {
736 Thread.sleep(delay);
737 } catch (Exception e0) {
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700738 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700739 }
740 }
741 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700742 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800743}