blob: 01cca31dac585a4db5d428435822dff47695c274 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00006import java.util.LinkedList;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -08007import java.util.List;
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 Radoslavov05378272013-10-19 23:23:05 -070022import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070023import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070024import net.onrc.onos.ofcontroller.core.INetMapStorage;
25import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
26import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070027import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070028import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080029import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070030import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070031import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080032
Naoki Shiota1a37ca12013-11-18 10:55:23 -080033import org.openflow.protocol.OFType;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080034import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
admin944ef4f2013-10-08 17:48:37 -070037/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070038 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070039 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070040public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080041 protected GraphDBOperation dbHandlerApi;
42 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080043
Jonathan Hart50a94982013-04-10 14:49:51 -070044 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070045 protected volatile IDatagridService datagridService;
46 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070047 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070048 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049
Brian O'Connor8c166a72013-11-14 18:41:48 -080050 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080051
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000052 // Flow Entry ID generation state
53 private static Random randomGenerator = new Random();
54 private static int nextFlowEntryIdPrefix = 0;
55 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000056
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080057 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070058 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080060 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080061 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
62 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080063 FlowDatabaseWriter flowDatabaseWriter;
64
admin944ef4f2013-10-08 17:48:37 -070065 /**
66 * Initialize the Flow Manager.
67 *
68 * @param conf the Graph Database configuration string.
69 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070 @Override
71 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080072 dbHandlerApi = new GraphDBOperation(conf);
73 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074 }
75
admin944ef4f2013-10-08 17:48:37 -070076 /**
77 * Shutdown the Flow Manager operation.
78 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080079 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070080 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080081 }
82
admin944ef4f2013-10-08 17:48:37 -070083 /**
84 * Shutdown the Flow Manager operation.
85 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080086 @Override
87 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070088 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080089 dbHandlerApi.close();
90 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080091 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080092
admin944ef4f2013-10-08 17:48:37 -070093 /**
94 * Get the collection of offered module services.
95 *
96 * @return the collection of offered module services.
97 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080098 @Override
99 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
100 Collection<Class<? extends IFloodlightService>> l =
101 new ArrayList<Class<? extends IFloodlightService>>();
102 l.add(IFlowService.class);
103 return l;
104 }
105
admin944ef4f2013-10-08 17:48:37 -0700106 /**
107 * Get the collection of implemented services.
108 *
109 * @return the collection of implemented services.
110 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800111 @Override
112 public Map<Class<? extends IFloodlightService>, IFloodlightService>
113 getServiceImpls() {
114 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700115 IFloodlightService> m =
116 new HashMap<Class<? extends IFloodlightService>,
117 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800118 m.put(IFlowService.class, this);
119 return m;
120 }
121
admin944ef4f2013-10-08 17:48:37 -0700122 /**
123 * Get the collection of modules this module depends on.
124 *
125 * @return the collection of modules this module depends on.
126 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800127 @Override
128 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700129 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800130 Collection<Class<? extends IFloodlightService>> l =
131 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800132 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700133 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700134 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800135 l.add(IRestApiService.class);
136 return l;
137 }
138
admin944ef4f2013-10-08 17:48:37 -0700139 /**
140 * Initialize the module.
141 *
142 * @param context the module context to use for the initialization.
143 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800144 @Override
145 public void init(FloodlightModuleContext context)
146 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700147 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800148 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700149 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800150 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800151 pusher = context.getServiceImpl(IFlowPusherService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800152
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700153 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800154 }
155
admin944ef4f2013-10-08 17:48:37 -0700156 /**
157 * Get the next Flow Entry ID to use.
158 *
159 * @return the next Flow Entry ID to use.
160 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800161 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700162 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000163 //
164 // Generate the next Flow Entry ID.
165 // NOTE: For now, the higher 32 bits are random, and
166 // the lower 32 bits are sequential.
167 // In the future, we need a better allocation mechanism.
168 //
169 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
170 nextFlowEntryIdPrefix = randomGenerator.nextInt();
171 nextFlowEntryIdSuffix = 0;
172 } else {
173 nextFlowEntryIdSuffix++;
174 }
175 long result = (long)nextFlowEntryIdPrefix << 32;
176 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
177 return result;
178 }
179
admin944ef4f2013-10-08 17:48:37 -0700180 /**
181 * Startup module operation.
182 *
183 * @param context the module context to use for the startup.
184 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800185 @Override
186 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700187 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700188
admin944ef4f2013-10-08 17:48:37 -0700189 // Initialize the Flow Entry ID generator
190 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800191
192 //
193 // The thread to write to the database
194 //
195 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800196 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800197 flowDatabaseWriter.start();
198
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700199 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800200 // The Flow Event Handler thread:
201 // - create
202 // - register with the Datagrid Service
203 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700204 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700205 flowEventHandler = new FlowEventHandler(this, datagridService);
206 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700207 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800208 }
209
210 /**
211 * Add a flow.
212 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800213 * @param flowPath the Flow Path to install.
214 * @param flowId the return-by-reference Flow ID as assigned internally.
215 * @return true on success, otherwise false.
216 */
217 @Override
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700218 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700219 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700220 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700221 // in case the application didn't do it.
222 //
223 for (FlowEntry flowEntry : flowPath.flowEntries()) {
224 if (flowEntry.flowEntrySwitchState() ==
225 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
226 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
227 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700228 if (! flowEntry.isValidFlowId())
229 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700230 }
231
Pavlin Radoslavov67bf7622013-12-04 12:28:23 -0800232 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700233 datagridService.notificationSendFlowAdded(flowPath);
234 return true;
235 }
236 return false;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800237 }
238
239 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700240 * Add a flow entry to the Network MAP.
241 *
242 * @param flowObj the corresponding Flow Path object for the Flow Entry.
243 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700244 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700245 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700246 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov67bf7622013-12-04 12:28:23 -0800247 return FlowDatabaseOperation.addFlowEntry(dbHandlerInner, flowObj,
248 flowEntry);
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700249 }
250
251 /**
Pavlin Radoslavov7407ab52013-11-01 22:19:00 -0700252 * Delete a flow entry from the Network MAP.
253 *
254 * @param flowObj the corresponding Flow Path object for the Flow Entry.
255 * @param flowEntry the Flow Entry to delete.
256 * @return true on success, otherwise false.
257 */
258 private boolean deleteFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800259 return FlowDatabaseOperation.deleteFlowEntry(dbHandlerInner,
260 flowObj, flowEntry);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800261 }
262
263 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000264 * Delete all previously added flows.
265 *
266 * @return true on success, otherwise false.
267 */
268 @Override
269 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800270 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700271 datagridService.notificationSendAllFlowsRemoved();
272 return true;
273 }
274 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000275 }
276
277 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800278 * Delete a previously added flow.
279 *
280 * @param flowId the Flow ID of the flow to delete.
281 * @return true on success, otherwise false.
282 */
283 @Override
284 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800285 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700286 datagridService.notificationSendFlowRemoved(flowId);
287 return true;
288 }
289 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700290 }
291
292 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800293 * Get a previously added flow.
294 *
295 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800296 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800297 */
298 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800299 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800300 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700301 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800302
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700303 /**
304 * Get all installed flows by all installers.
305 *
306 * @return the Flow Paths if found, otherwise null.
307 */
308 @Override
309 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800310 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800311 }
312
313 /**
314 * Get all previously added flows by a specific installer for a given
315 * data path endpoints.
316 *
317 * @param installerId the Caller ID of the installer of the flow to get.
318 * @param dataPathEndpoints the data path endpoints of the flow to get.
319 * @return the Flow Paths if found, otherwise null.
320 */
321 @Override
322 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
323 DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800324 return FlowDatabaseOperation.getAllFlows(dbHandlerApi, installerId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700325 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800326 }
327
328 /**
329 * Get all installed flows by all installers for given data path endpoints.
330 *
331 * @param dataPathEndpoints the data path endpoints of the flows to get.
332 * @return the Flow Paths if found, otherwise null.
333 */
334 @Override
335 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800336 return FlowDatabaseOperation.getAllFlows(dbHandlerApi,
337 dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800338 }
339
340 /**
admin944ef4f2013-10-08 17:48:37 -0700341 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700342 *
admin944ef4f2013-10-08 17:48:37 -0700343 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700344 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700345 * @return the Flow Paths if found, otherwise null.
346 */
347 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800348 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
349 int maxFlows) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800350 return FlowDatabaseOperation.getAllFlowsSummary(dbHandlerApi, flowId,
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700351 maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700352 }
353
354 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700355 * Add and maintain a shortest-path flow.
356 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700357 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700358 *
359 * @param flowPath the Flow Path with the endpoints and the match
360 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700361 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700362 */
363 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700364 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700365 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +0000366 // Don't do the shortest path computation here.
367 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700368 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700369
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700370 FlowId flowId = new FlowId();
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700371 if (! addFlow(flowPath, flowId))
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700372 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700373
Pavlin Radoslavovbcc86ef2013-10-26 12:06:25 -0700374 return (flowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700375 }
376
377 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800378 * Get the collection of my switches.
379 *
380 * @return the collection of my switches.
381 */
382 public Map<Long, IOFSwitch> getMySwitches() {
383 return floodlightProvider.getSwitches();
384 }
385
386 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800387 * Get the network topology.
388 *
389 * @return the network topology.
390 */
391 public Topology getTopology() {
392 return flowEventHandler.getTopology();
393 }
394
395 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800396 * Inform the Flow Manager that a Flow Entry on switch expired.
397 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800398 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800399 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
400 */
Brian O'Connor4f0b60c2013-11-26 15:00:04 -0800401 public void flowEntryOnSwitchExpired(IOFSwitch sw, FlowEntryId flowEntryId) {
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800402 // TODO: Not implemented yet
403 }
404
405 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800406 * Inform the Flow Manager that a collection of Flow Entries have been
407 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800408 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800409 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
410 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800411 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800412 public void flowEntriesPushedToSwitch(
413 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800414
415 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800416 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800417 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800418 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
419 IOFSwitch sw = entry.left;
420 FlowEntry flowEntry = entry.right;
421
422 //
423 // Mark the Flow Entry that it has been pushed to the switch
424 //
425 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
426
427 //
428 // Write the Flow Entry to the Datagrid
429 //
430 switch (flowEntry.flowEntryUserState()) {
431 case FE_USER_ADD:
432 datagridService.notificationSendFlowEntryAdded(flowEntry);
433 break;
434 case FE_USER_MODIFY:
435 datagridService.notificationSendFlowEntryUpdated(flowEntry);
436 break;
437 case FE_USER_DELETE:
438 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
439 break;
440 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800441 }
442 }
443
444 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800445 * Push modified Flow-related state as appropriate.
446 *
447 * @param modifiedFlowPaths the collection of modified Flow Paths.
448 * @param modifiedFlowEntries the collection of modified Flow Entries.
449 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800450 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
451 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800452 //
453 // Push the modified Flow state:
454 // - Flow Entries to switches and the datagrid
455 // - Flow Paths to the database
456 //
457 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800458 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800459 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800460 }
461
462 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800463 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700464 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800465 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700466 * are pushed.
467 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800468 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700469 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800470 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800471 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800472 if (modifiedFlowEntries.isEmpty())
473 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700474
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800475 List<Pair<IOFSwitch, FlowEntry>> entries =
476 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
477
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800478 Map<Long, IOFSwitch> mySwitches = getMySwitches();
479
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800480 //
481 // Create a collection of my Flow Entries to push
482 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800483 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800484 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
485 if (mySwitch == null)
486 continue;
487
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800488 //
489 // Assign Flow Entry IDs if missing.
490 //
491 // NOTE: This is an additional safeguard, in case the
492 // mySwitches set has changed (after the Flow Entry IDs
493 // assignments by the caller).
494 //
495 if (! flowEntry.isValidFlowEntryId()) {
496 long id = getNextFlowEntryId();
497 flowEntry.setFlowEntryId(new FlowEntryId(id));
498 }
499
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800500 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800501 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800502 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800503
504 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800505 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700506
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800508 * Cleanup deleted Flow Entries from the datagrid.
509 *
510 * NOTE: We cleanup only the Flow Entries that are not for our switches.
511 * This is needed to handle the case a switch going down:
512 * It has no Master controller instance, hence no controller instance
513 * will cleanup its flow entries.
514 * This is sub-optimal: we need to elect a controller instance to handle
515 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800516 *
517 * @param modifiedFlowEntries the collection of modified Flow Entries.
518 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800519 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800520 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800521 if (modifiedFlowEntries.isEmpty())
522 return;
523
524 Map<Long, IOFSwitch> mySwitches = getMySwitches();
525
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800526 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800527 //
528 // Process only Flow Entries that should be deleted and have
529 // a valid Flow Entry ID.
530 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800531 if (! flowEntry.isValidFlowEntryId())
532 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800533 if (flowEntry.flowEntryUserState() !=
534 FlowEntryUserState.FE_USER_DELETE) {
535 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800536 }
537
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800538 //
539 // NOTE: The deletion of Flow Entries for my switches is handled
540 // elsewhere.
541 //
542 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
543 if (mySwitch != null)
544 continue;
545
546 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
547
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800548 //
549 // Write the Flow Entry to the Datagrid
550 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800551 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800552 }
553 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700554
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800555 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800556 * Class to implement writing to the database in a separate thread.
557 */
558 class FlowDatabaseWriter extends Thread {
559 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800560 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800561
562 /**
563 * Constructor.
564 *
565 * @param flowManager the Flow Manager to use.
566 * @param blockingQueue the blocking queue to use.
567 */
568 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800569 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800570 this.flowManager = flowManager;
571 this.blockingQueue = blockingQueue;
572 }
573
574 /**
575 * Run the thread.
576 */
577 @Override
578 public void run() {
579 //
580 // The main loop
581 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800582 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800583 try {
584 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800585 FlowPath flowPath = blockingQueue.take();
586 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800587 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800588 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800589 collection.clear();
590 }
591 } catch (Exception exception) {
592 log.debug("Exception writing to the Database: ", exception);
593 }
594 }
595 }
596
597 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800598 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800599 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800600 * NOTE: The complete Flow Paths are pushed only on the instance
601 * responsible for the first switch. This is to avoid database errors
602 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800603 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800604 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800605 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800606 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800607 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800608 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800609 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800610 // The FlowDatabaseWriter thread is responsible for the actual writing.
611 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800612 flowPathsToDatabaseQueue.addAll(modifiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800613 }
614
615 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800616 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800617 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800618 * NOTE: The complete Flow Paths are pushed only on the instance
619 * responsible for the first switch. This is to avoid database errors
620 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800621 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800622 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800623 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800624 private void writeModifiedFlowPathsToDatabase(
625 Collection<FlowPath> modifiedFlowPaths) {
626 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800627 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700628
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800629 FlowId dummyFlowId = new FlowId();
630
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800631 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700632
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800633 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800634 //
Pavlin Radoslavov409c9fa2013-12-04 19:16:41 -0800635 // Don't push Flow Paths that are deleted by the user.
636 // Those will be deleted at the ONOS instance that received the
637 // API call to delete the flow.
638 //
639 if (flowPath.flowPathUserState() ==
640 FlowPathUserState.FP_USER_DELETE) {
641 continue;
642 }
643
644 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800645 // Push the changes only on the instance responsible for the
646 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800647 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800648 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
649 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
650 if (mySrcSwitch == null)
651 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800652
653 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800654 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800655 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800656 boolean allValid = true;
657 for (FlowEntry flowEntry : flowPath.flowEntries()) {
658 if (flowEntry.flowEntryUserState() ==
659 FlowEntryUserState.FE_USER_DELETE) {
660 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700661 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800662 if (! flowEntry.isValidFlowEntryId()) {
663 allValid = false;
664 break;
665 }
666 }
667 if (! allValid)
668 continue;
669
670 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
671
672 //
673 // Write the Flow Path to the Network Map
674 //
675 try {
Pavlin Radoslavov67bf7622013-12-04 12:28:23 -0800676 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath,
677 dummyFlowId)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800678 String logMsg = "Cannot write to Network Map Flow Path " +
679 flowPath.flowId();
680 log.error(logMsg);
681 }
682 } catch (Exception e) {
683 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700684 }
685 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700686 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800687}