blob: 055a5b31c8c781a838844f96f5477479076fe18d [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 Radoslavovc0862662013-12-10 15:31:49 -080031import net.onrc.onos.ofcontroller.forwarding.IForwardingService;
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
Naoki Shiota1a37ca12013-11-18 10:55:23 -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 {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080043 protected GraphDBOperation dbHandlerApi;
44 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080045
Jonathan Hart50a94982013-04-10 14:49:51 -070046 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070047 protected volatile IDatagridService datagridService;
48 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070049 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070050 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080051
Brian O'Connor8c166a72013-11-14 18:41:48 -080052 protected IFlowPusherService pusher;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080053
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000054 // Flow Entry ID generation state
55 private static Random randomGenerator = new Random();
56 private static int nextFlowEntryIdPrefix = 0;
57 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000058
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070060 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080061
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080062 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080063 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
64 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080065 FlowDatabaseWriter flowDatabaseWriter;
66
admin944ef4f2013-10-08 17:48:37 -070067 /**
68 * Initialize the Flow Manager.
69 *
70 * @param conf the Graph Database configuration string.
71 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 @Override
73 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080074 dbHandlerApi = new GraphDBOperation(conf);
75 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080076 }
77
admin944ef4f2013-10-08 17:48:37 -070078 /**
79 * Shutdown the Flow Manager operation.
80 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080081 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070082 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080083 }
84
admin944ef4f2013-10-08 17:48:37 -070085 /**
86 * Shutdown the Flow Manager operation.
87 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080088 @Override
89 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070090 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080091 dbHandlerApi.close();
92 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080094
admin944ef4f2013-10-08 17:48:37 -070095 /**
96 * Get the collection of offered module services.
97 *
98 * @return the collection of offered module services.
99 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800100 @Override
101 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
102 Collection<Class<? extends IFloodlightService>> l =
103 new ArrayList<Class<? extends IFloodlightService>>();
104 l.add(IFlowService.class);
105 return l;
106 }
107
admin944ef4f2013-10-08 17:48:37 -0700108 /**
109 * Get the collection of implemented services.
110 *
111 * @return the collection of implemented services.
112 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800113 @Override
114 public Map<Class<? extends IFloodlightService>, IFloodlightService>
115 getServiceImpls() {
116 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700117 IFloodlightService> m =
118 new HashMap<Class<? extends IFloodlightService>,
119 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800120 m.put(IFlowService.class, this);
121 return m;
122 }
123
admin944ef4f2013-10-08 17:48:37 -0700124 /**
125 * Get the collection of modules this module depends on.
126 *
127 * @return the collection of modules this module depends on.
128 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800129 @Override
130 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700131 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800132 Collection<Class<? extends IFloodlightService>> l =
133 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800134 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700135 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700136 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800137 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800138 l.add(IFlowPusherService.class);
139 l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800140 return l;
141 }
142
admin944ef4f2013-10-08 17:48:37 -0700143 /**
144 * Initialize the module.
145 *
146 * @param context the module context to use for the initialization.
147 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800148 @Override
149 public void init(FloodlightModuleContext context)
150 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700151 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800152 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700153 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800154 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800155 pusher = context.getServiceImpl(IFlowPusherService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800156
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700157 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800158 }
159
admin944ef4f2013-10-08 17:48:37 -0700160 /**
161 * Get the next Flow Entry ID to use.
162 *
163 * @return the next Flow Entry ID to use.
164 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800165 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700166 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000167 //
168 // Generate the next Flow Entry ID.
169 // NOTE: For now, the higher 32 bits are random, and
170 // the lower 32 bits are sequential.
171 // In the future, we need a better allocation mechanism.
172 //
173 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
174 nextFlowEntryIdPrefix = randomGenerator.nextInt();
175 nextFlowEntryIdSuffix = 0;
176 } else {
177 nextFlowEntryIdSuffix++;
178 }
179 long result = (long)nextFlowEntryIdPrefix << 32;
180 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
181 return result;
182 }
183
admin944ef4f2013-10-08 17:48:37 -0700184 /**
185 * Startup module operation.
186 *
187 * @param context the module context to use for the startup.
188 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800189 @Override
190 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700191 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700192
admin944ef4f2013-10-08 17:48:37 -0700193 // Initialize the Flow Entry ID generator
194 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800195
196 //
197 // The thread to write to the database
198 //
199 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800200 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800201 flowDatabaseWriter.start();
202
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700203 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800204 // The Flow Event Handler thread:
205 // - create
206 // - register with the Datagrid Service
207 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700208 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700209 flowEventHandler = new FlowEventHandler(this, datagridService);
210 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700211 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800212 }
213
214 /**
215 * Add a flow.
216 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800217 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800218 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800219 */
220 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800221 public FlowId addFlow(FlowPath flowPath) {
222
223 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800224 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800225 long id = getNextFlowEntryId();
226 flowPath.setFlowId(new FlowId(id));
227 }
228
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700229 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700230 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700231 // in case the application didn't do it.
232 //
233 for (FlowEntry flowEntry : flowPath.flowEntries()) {
234 if (flowEntry.flowEntrySwitchState() ==
235 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
236 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
237 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700238 if (! flowEntry.isValidFlowId())
239 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700240 }
241
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800242 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700243 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800244 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700245 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800246 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800247 }
248
249 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000250 * Delete all previously added flows.
251 *
252 * @return true on success, otherwise false.
253 */
254 @Override
255 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800256 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700257 datagridService.notificationSendAllFlowsRemoved();
258 return true;
259 }
260 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000261 }
262
263 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800264 * Delete a previously added flow.
265 *
266 * @param flowId the Flow ID of the flow to delete.
267 * @return true on success, otherwise false.
268 */
269 @Override
270 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800271 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700272 datagridService.notificationSendFlowRemoved(flowId);
273 return true;
274 }
275 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700276 }
277
278 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800279 * Get a previously added flow.
280 *
281 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800282 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800283 */
284 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800285 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800286 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700287 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800288
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700289 /**
290 * Get all installed flows by all installers.
291 *
292 * @return the Flow Paths if found, otherwise null.
293 */
294 @Override
295 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800296 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800297 }
298
299 /**
admin944ef4f2013-10-08 17:48:37 -0700300 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700301 *
admin944ef4f2013-10-08 17:48:37 -0700302 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700303 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700304 * @return the Flow Paths if found, otherwise null.
305 */
306 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800307 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
308 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800309 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
310 SortedMap<Long, FlowPath> sortedFlowPaths =
311 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800312
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800313 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800314 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800315 //
316 for (FlowPath flowPath : sortedFlowPaths.values()) {
317 //
318 // TODO: Add only the Flow Paths that have been successfully
319 // installed.
320 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800321 flowPath.setFlowEntryMatch(null);
322 flowPath.setFlowEntryActions(null);
323 for (FlowEntry flowEntry : flowPath.flowEntries()) {
324 flowEntry.setFlowEntryMatch(null);
325 flowEntry.setFlowEntryActions(null);
326 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800327 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800328 }
329
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800330 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700331 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700332
333 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800334 * Get the collection of my switches.
335 *
336 * @return the collection of my switches.
337 */
338 public Map<Long, IOFSwitch> getMySwitches() {
339 return floodlightProvider.getSwitches();
340 }
341
342 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800343 * Get the network topology.
344 *
345 * @return the network topology.
346 */
347 public Topology getTopology() {
348 return flowEventHandler.getTopology();
349 }
350
351 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800352 * Inform the Flow Manager that a Flow Entry on switch expired.
353 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800354 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800355 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
356 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800357 public void flowEntryOnSwitchExpired(IOFSwitch sw,
358 FlowEntryId flowEntryId) {
359 // Find the Flow Entry
360 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
361 if (flowEntryId == null)
362 return; // Flow Entry not found
363
364 // Find the Flow Path
365 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
366 if (flowPath == null)
367 return; // Flow Path not found
368
369 //
370 // Remove the Flow if the Flow Entry expired on the first switch
371 //
372 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
373 if (srcDpid.value() != sw.getId())
374 return;
375 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800376 }
377
378 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800379 * Inform the Flow Manager that a collection of Flow Entries have been
380 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800381 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800382 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
383 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800384 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800385 public void flowEntriesPushedToSwitch(
386 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800387
388 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800389 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800390 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800391 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800392 IOFSwitch sw = entry.first;
393 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800394
395 //
396 // Mark the Flow Entry that it has been pushed to the switch
397 //
398 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
399
400 //
401 // Write the Flow Entry to the Datagrid
402 //
403 switch (flowEntry.flowEntryUserState()) {
404 case FE_USER_ADD:
405 datagridService.notificationSendFlowEntryAdded(flowEntry);
406 break;
407 case FE_USER_MODIFY:
408 datagridService.notificationSendFlowEntryUpdated(flowEntry);
409 break;
410 case FE_USER_DELETE:
411 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
412 break;
413 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800414 }
415 }
416
417 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800418 * Push modified Flow-related state as appropriate.
419 *
420 * @param modifiedFlowPaths the collection of modified Flow Paths.
421 * @param modifiedFlowEntries the collection of modified Flow Entries.
422 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800423 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
424 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800425 //
426 // Push the modified Flow state:
427 // - Flow Entries to switches and the datagrid
428 // - Flow Paths to the database
429 //
430 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800431 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800432 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800433 }
434
435 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800436 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700437 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800438 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700439 * are pushed.
440 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800441 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700442 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800443 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800444 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800445 if (modifiedFlowEntries.isEmpty())
446 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700447
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800448 List<Pair<IOFSwitch, FlowEntry>> entries =
449 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
450
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800451 Map<Long, IOFSwitch> mySwitches = getMySwitches();
452
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800453 //
454 // Create a collection of my Flow Entries to push
455 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800456 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800457 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
458 if (mySwitch == null)
459 continue;
460
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800461 //
462 // Assign Flow Entry IDs if missing.
463 //
464 // NOTE: This is an additional safeguard, in case the
465 // mySwitches set has changed (after the Flow Entry IDs
466 // assignments by the caller).
467 //
468 if (! flowEntry.isValidFlowEntryId()) {
469 long id = getNextFlowEntryId();
470 flowEntry.setFlowEntryId(new FlowEntryId(id));
471 }
472
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800473 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800474 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800475 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800476
477 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800478 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700479
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800480 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800481 * Cleanup deleted Flow Entries from the datagrid.
482 *
483 * NOTE: We cleanup only the Flow Entries that are not for our switches.
484 * This is needed to handle the case a switch going down:
485 * It has no Master controller instance, hence no controller instance
486 * will cleanup its flow entries.
487 * This is sub-optimal: we need to elect a controller instance to handle
488 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800489 *
490 * @param modifiedFlowEntries the collection of modified Flow Entries.
491 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800492 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800493 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800494 if (modifiedFlowEntries.isEmpty())
495 return;
496
497 Map<Long, IOFSwitch> mySwitches = getMySwitches();
498
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800499 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800500 //
501 // Process only Flow Entries that should be deleted and have
502 // a valid Flow Entry ID.
503 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800504 if (! flowEntry.isValidFlowEntryId())
505 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800506 if (flowEntry.flowEntryUserState() !=
507 FlowEntryUserState.FE_USER_DELETE) {
508 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800509 }
510
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800511 //
512 // NOTE: The deletion of Flow Entries for my switches is handled
513 // elsewhere.
514 //
515 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
516 if (mySwitch != null)
517 continue;
518
519 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
520
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800521 //
522 // Write the Flow Entry to the Datagrid
523 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800524 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800525 }
526 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700527
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800528 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800529 * Class to implement writing to the database in a separate thread.
530 */
531 class FlowDatabaseWriter extends Thread {
532 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800533 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800534
535 /**
536 * Constructor.
537 *
538 * @param flowManager the Flow Manager to use.
539 * @param blockingQueue the blocking queue to use.
540 */
541 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800542 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800543 this.flowManager = flowManager;
544 this.blockingQueue = blockingQueue;
545 }
546
547 /**
548 * Run the thread.
549 */
550 @Override
551 public void run() {
552 //
553 // The main loop
554 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800555 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800556 try {
557 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800558 FlowPath flowPath = blockingQueue.take();
559 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800560 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800561 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800562 collection.clear();
563 }
564 } catch (Exception exception) {
565 log.debug("Exception writing to the Database: ", exception);
566 }
567 }
568 }
569
570 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800571 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800572 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800573 * NOTE: The complete Flow Paths are pushed only on the instance
574 * responsible for the first switch. This is to avoid database errors
575 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800576 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800577 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800578 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800579 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800580 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800581 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800582 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800583 // The FlowDatabaseWriter thread is responsible for the actual writing.
584 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800585 flowPathsToDatabaseQueue.addAll(modifiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800586 }
587
588 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800589 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800590 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800591 * NOTE: The complete Flow Paths are pushed only on the instance
592 * responsible for the first switch. This is to avoid database errors
593 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800594 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800595 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800596 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800597 private void writeModifiedFlowPathsToDatabase(
598 Collection<FlowPath> modifiedFlowPaths) {
599 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800600 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700601
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800602 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700603
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800604 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800605 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800606 // Push the changes only on the instance responsible for the
607 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800608 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800609 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
610 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
611 if (mySrcSwitch == null)
612 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800613
614 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800615 // Delete the Flow Path from the Network Map
616 //
617 if (flowPath.flowPathUserState() ==
618 FlowPathUserState.FP_USER_DELETE) {
619 log.debug("Deleting Flow Path From Database: {}",
620 flowPath.toString());
621
622 try {
623 if (! FlowDatabaseOperation.deleteFlow(
624 dbHandlerInner,
625 flowPath.flowId())) {
626 log.error("Cannot delete Flow Path {} from Network Map",
627 flowPath.flowId());
628 }
629 } catch (Exception e) {
630 log.error("Exception deleting Flow Path from Network MAP: {}", e);
631 }
632 continue;
633 }
634
635 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800636 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800637 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800638 boolean allValid = true;
639 for (FlowEntry flowEntry : flowPath.flowEntries()) {
640 if (flowEntry.flowEntryUserState() ==
641 FlowEntryUserState.FE_USER_DELETE) {
642 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700643 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800644 if (! flowEntry.isValidFlowEntryId()) {
645 allValid = false;
646 break;
647 }
648 }
649 if (! allValid)
650 continue;
651
652 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
653
654 //
655 // Write the Flow Path to the Network Map
656 //
657 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800658 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800659 String logMsg = "Cannot write to Network Map Flow Path " +
660 flowPath.flowId();
661 log.error(logMsg);
662 }
663 } catch (Exception e) {
664 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700665 }
666 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700667 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800668}