blob: 7ef49ef95c35bacf900aafc9103d008b96446c86 [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 Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080011import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080012import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080015
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080018import net.floodlightcontroller.core.module.FloodlightModuleContext;
19import net.floodlightcontroller.core.module.FloodlightModuleException;
20import net.floodlightcontroller.core.module.IFloodlightModule;
21import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022import net.floodlightcontroller.restserver.IRestApiService;
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 {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080042 protected GraphDBOperation dbHandlerApi;
43 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080044
Jonathan Hart50a94982013-04-10 14:49:51 -070045 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070046 protected volatile IDatagridService datagridService;
47 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070048 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070049 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080050
Brian O'Connor8c166a72013-11-14 18:41:48 -080051 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080052
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000053 // Flow Entry ID generation state
54 private static Random randomGenerator = new Random();
55 private static int nextFlowEntryIdPrefix = 0;
56 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000057
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080058 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070059 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080060
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080061 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080062 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
63 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080064 FlowDatabaseWriter flowDatabaseWriter;
65
admin944ef4f2013-10-08 17:48:37 -070066 /**
67 * Initialize the Flow Manager.
68 *
69 * @param conf the Graph Database configuration string.
70 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071 @Override
72 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080073 dbHandlerApi = new GraphDBOperation(conf);
74 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075 }
76
admin944ef4f2013-10-08 17:48:37 -070077 /**
78 * Shutdown the Flow Manager operation.
79 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080080 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070081 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080082 }
83
admin944ef4f2013-10-08 17:48:37 -070084 /**
85 * Shutdown the Flow Manager operation.
86 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080087 @Override
88 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070089 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080090 dbHandlerApi.close();
91 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080092 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080093
admin944ef4f2013-10-08 17:48:37 -070094 /**
95 * Get the collection of offered module services.
96 *
97 * @return the collection of offered module services.
98 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080099 @Override
100 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
101 Collection<Class<? extends IFloodlightService>> l =
102 new ArrayList<Class<? extends IFloodlightService>>();
103 l.add(IFlowService.class);
104 return l;
105 }
106
admin944ef4f2013-10-08 17:48:37 -0700107 /**
108 * Get the collection of implemented services.
109 *
110 * @return the collection of implemented services.
111 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800112 @Override
113 public Map<Class<? extends IFloodlightService>, IFloodlightService>
114 getServiceImpls() {
115 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700116 IFloodlightService> m =
117 new HashMap<Class<? extends IFloodlightService>,
118 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800119 m.put(IFlowService.class, this);
120 return m;
121 }
122
admin944ef4f2013-10-08 17:48:37 -0700123 /**
124 * Get the collection of modules this module depends on.
125 *
126 * @return the collection of modules this module depends on.
127 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800128 @Override
129 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700130 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800131 Collection<Class<? extends IFloodlightService>> l =
132 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800133 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700134 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700135 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800136 l.add(IRestApiService.class);
Jonathan Hart6968fb32013-12-07 17:29:37 -0800137 l.add(IFlowPusherService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800138 return l;
139 }
140
admin944ef4f2013-10-08 17:48:37 -0700141 /**
142 * Initialize the module.
143 *
144 * @param context the module context to use for the initialization.
145 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800146 @Override
147 public void init(FloodlightModuleContext context)
148 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700149 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800150 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700151 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800152 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800153 pusher = context.getServiceImpl(IFlowPusherService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800154
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700155 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800156 }
157
admin944ef4f2013-10-08 17:48:37 -0700158 /**
159 * Get the next Flow Entry ID to use.
160 *
161 * @return the next Flow Entry ID to use.
162 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800163 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700164 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000165 //
166 // Generate the next Flow Entry ID.
167 // NOTE: For now, the higher 32 bits are random, and
168 // the lower 32 bits are sequential.
169 // In the future, we need a better allocation mechanism.
170 //
171 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
172 nextFlowEntryIdPrefix = randomGenerator.nextInt();
173 nextFlowEntryIdSuffix = 0;
174 } else {
175 nextFlowEntryIdSuffix++;
176 }
177 long result = (long)nextFlowEntryIdPrefix << 32;
178 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
179 return result;
180 }
181
admin944ef4f2013-10-08 17:48:37 -0700182 /**
183 * Startup module operation.
184 *
185 * @param context the module context to use for the startup.
186 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800187 @Override
188 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700189 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700190
admin944ef4f2013-10-08 17:48:37 -0700191 // Initialize the Flow Entry ID generator
192 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800193
194 //
195 // The thread to write to the database
196 //
197 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800198 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800199 flowDatabaseWriter.start();
200
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700201 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800202 // The Flow Event Handler thread:
203 // - create
204 // - register with the Datagrid Service
205 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700206 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700207 flowEventHandler = new FlowEventHandler(this, datagridService);
208 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700209 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800210 }
211
212 /**
213 * Add a flow.
214 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800215 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800216 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800217 */
218 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800219 public FlowId addFlow(FlowPath flowPath) {
220
221 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800222 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800223 long id = getNextFlowEntryId();
224 flowPath.setFlowId(new FlowId(id));
225 }
226
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700227 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700228 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700229 // in case the application didn't do it.
230 //
231 for (FlowEntry flowEntry : flowPath.flowEntries()) {
232 if (flowEntry.flowEntrySwitchState() ==
233 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
234 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
235 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700236 if (! flowEntry.isValidFlowId())
237 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700238 }
239
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800240 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700241 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800242 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700243 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800244 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800245 }
246
247 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000248 * Delete all previously added flows.
249 *
250 * @return true on success, otherwise false.
251 */
252 @Override
253 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800254 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700255 datagridService.notificationSendAllFlowsRemoved();
256 return true;
257 }
258 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000259 }
260
261 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800262 * Delete a previously added flow.
263 *
264 * @param flowId the Flow ID of the flow to delete.
265 * @return true on success, otherwise false.
266 */
267 @Override
268 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800269 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700270 datagridService.notificationSendFlowRemoved(flowId);
271 return true;
272 }
273 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700274 }
275
276 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800277 * Get a previously added flow.
278 *
279 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800280 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800281 */
282 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800283 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800284 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700285 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800286
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700287 /**
288 * Get all installed flows by all installers.
289 *
290 * @return the Flow Paths if found, otherwise null.
291 */
292 @Override
293 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800294 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800295 }
296
297 /**
admin944ef4f2013-10-08 17:48:37 -0700298 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700299 *
admin944ef4f2013-10-08 17:48:37 -0700300 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700301 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700302 * @return the Flow Paths if found, otherwise null.
303 */
304 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800305 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
306 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800307 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
308 SortedMap<Long, FlowPath> sortedFlowPaths =
309 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800310
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800311 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800312 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800313 //
314 for (FlowPath flowPath : sortedFlowPaths.values()) {
315 //
316 // TODO: Add only the Flow Paths that have been successfully
317 // installed.
318 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800319 flowPath.setFlowEntryMatch(null);
320 flowPath.setFlowEntryActions(null);
321 for (FlowEntry flowEntry : flowPath.flowEntries()) {
322 flowEntry.setFlowEntryMatch(null);
323 flowEntry.setFlowEntryActions(null);
324 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800325 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800326 }
327
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800328 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700329 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700330
331 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800332 * Get the collection of my switches.
333 *
334 * @return the collection of my switches.
335 */
336 public Map<Long, IOFSwitch> getMySwitches() {
337 return floodlightProvider.getSwitches();
338 }
339
340 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800341 * Get the network topology.
342 *
343 * @return the network topology.
344 */
345 public Topology getTopology() {
346 return flowEventHandler.getTopology();
347 }
348
349 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800350 * Inform the Flow Manager that a Flow Entry on switch expired.
351 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800352 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800353 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
354 */
Brian O'Connor4f0b60c2013-11-26 15:00:04 -0800355 public void flowEntryOnSwitchExpired(IOFSwitch sw, FlowEntryId flowEntryId) {
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800356 // TODO: Not implemented yet
357 }
358
359 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800360 * Inform the Flow Manager that a collection of Flow Entries have been
361 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800362 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800363 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
364 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800365 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800366 public void flowEntriesPushedToSwitch(
367 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800368
369 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800370 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800371 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800372 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800373 IOFSwitch sw = entry.first;
374 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800375
376 //
377 // Mark the Flow Entry that it has been pushed to the switch
378 //
379 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
380
381 //
382 // Write the Flow Entry to the Datagrid
383 //
384 switch (flowEntry.flowEntryUserState()) {
385 case FE_USER_ADD:
386 datagridService.notificationSendFlowEntryAdded(flowEntry);
387 break;
388 case FE_USER_MODIFY:
389 datagridService.notificationSendFlowEntryUpdated(flowEntry);
390 break;
391 case FE_USER_DELETE:
392 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
393 break;
394 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800395 }
396 }
397
398 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800399 * Push modified Flow-related state as appropriate.
400 *
401 * @param modifiedFlowPaths the collection of modified Flow Paths.
402 * @param modifiedFlowEntries the collection of modified Flow Entries.
403 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800404 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
405 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800406 //
407 // Push the modified Flow state:
408 // - Flow Entries to switches and the datagrid
409 // - Flow Paths to the database
410 //
411 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800412 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800413 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800414 }
415
416 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800417 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700418 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800419 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700420 * are pushed.
421 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800422 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700423 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800424 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800425 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800426 if (modifiedFlowEntries.isEmpty())
427 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700428
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800429 List<Pair<IOFSwitch, FlowEntry>> entries =
430 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
431
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800432 Map<Long, IOFSwitch> mySwitches = getMySwitches();
433
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800434 //
435 // Create a collection of my Flow Entries to push
436 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800437 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800438 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
439 if (mySwitch == null)
440 continue;
441
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800442 //
443 // Assign Flow Entry IDs if missing.
444 //
445 // NOTE: This is an additional safeguard, in case the
446 // mySwitches set has changed (after the Flow Entry IDs
447 // assignments by the caller).
448 //
449 if (! flowEntry.isValidFlowEntryId()) {
450 long id = getNextFlowEntryId();
451 flowEntry.setFlowEntryId(new FlowEntryId(id));
452 }
453
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800454 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800455 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800456 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800457
458 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800459 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700460
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800461 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800462 * Cleanup deleted Flow Entries from the datagrid.
463 *
464 * NOTE: We cleanup only the Flow Entries that are not for our switches.
465 * This is needed to handle the case a switch going down:
466 * It has no Master controller instance, hence no controller instance
467 * will cleanup its flow entries.
468 * This is sub-optimal: we need to elect a controller instance to handle
469 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800470 *
471 * @param modifiedFlowEntries the collection of modified Flow Entries.
472 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800473 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800474 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800475 if (modifiedFlowEntries.isEmpty())
476 return;
477
478 Map<Long, IOFSwitch> mySwitches = getMySwitches();
479
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800480 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800481 //
482 // Process only Flow Entries that should be deleted and have
483 // a valid Flow Entry ID.
484 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800485 if (! flowEntry.isValidFlowEntryId())
486 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800487 if (flowEntry.flowEntryUserState() !=
488 FlowEntryUserState.FE_USER_DELETE) {
489 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800490 }
491
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800492 //
493 // NOTE: The deletion of Flow Entries for my switches is handled
494 // elsewhere.
495 //
496 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
497 if (mySwitch != null)
498 continue;
499
500 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
501
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800502 //
503 // Write the Flow Entry to the Datagrid
504 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800505 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800506 }
507 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700508
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800509 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800510 * Class to implement writing to the database in a separate thread.
511 */
512 class FlowDatabaseWriter extends Thread {
513 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800514 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800515
516 /**
517 * Constructor.
518 *
519 * @param flowManager the Flow Manager to use.
520 * @param blockingQueue the blocking queue to use.
521 */
522 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800523 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800524 this.flowManager = flowManager;
525 this.blockingQueue = blockingQueue;
526 }
527
528 /**
529 * Run the thread.
530 */
531 @Override
532 public void run() {
533 //
534 // The main loop
535 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800536 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800537 try {
538 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800539 FlowPath flowPath = blockingQueue.take();
540 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800541 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800542 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800543 collection.clear();
544 }
545 } catch (Exception exception) {
546 log.debug("Exception writing to the Database: ", exception);
547 }
548 }
549 }
550
551 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800552 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800553 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800554 * NOTE: The complete Flow Paths are pushed only on the instance
555 * responsible for the first switch. This is to avoid database errors
556 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800557 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800558 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800559 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800560 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800561 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800562 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800563 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800564 // The FlowDatabaseWriter thread is responsible for the actual writing.
565 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800566 flowPathsToDatabaseQueue.addAll(modifiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800567 }
568
569 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800570 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800571 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800572 * NOTE: The complete Flow Paths are pushed only on the instance
573 * responsible for the first switch. This is to avoid database errors
574 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800575 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800576 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800577 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800578 private void writeModifiedFlowPathsToDatabase(
579 Collection<FlowPath> modifiedFlowPaths) {
580 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800581 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700582
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800583 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700584
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800585 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800586 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800587 // Push the changes only on the instance responsible for the
588 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800589 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800590 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
591 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
592 if (mySrcSwitch == null)
593 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800594
595 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800596 // Delete the Flow Path from the Network Map
597 //
598 if (flowPath.flowPathUserState() ==
599 FlowPathUserState.FP_USER_DELETE) {
600 log.debug("Deleting Flow Path From Database: {}",
601 flowPath.toString());
602
603 try {
604 if (! FlowDatabaseOperation.deleteFlow(
605 dbHandlerInner,
606 flowPath.flowId())) {
607 log.error("Cannot delete Flow Path {} from Network Map",
608 flowPath.flowId());
609 }
610 } catch (Exception e) {
611 log.error("Exception deleting Flow Path from Network MAP: {}", e);
612 }
613 continue;
614 }
615
616 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800617 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800618 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800619 boolean allValid = true;
620 for (FlowEntry flowEntry : flowPath.flowEntries()) {
621 if (flowEntry.flowEntryUserState() ==
622 FlowEntryUserState.FE_USER_DELETE) {
623 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700624 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800625 if (! flowEntry.isValidFlowEntryId()) {
626 allValid = false;
627 break;
628 }
629 }
630 if (! allValid)
631 continue;
632
633 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
634
635 //
636 // Write the Flow Path to the Network Map
637 //
638 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800639 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800640 String logMsg = "Cannot write to Network Map Flow Path " +
641 flowPath.flowId();
642 log.error(logMsg);
643 }
644 } catch (Exception e) {
645 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700646 }
647 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700648 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800649}