blob: 67d16f770424ea184923fdad3e0edde57430ce9c [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 Radoslavov9e5344c2013-02-18 09:58:30 -080013
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080016import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070021import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070022import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070023import net.onrc.onos.ofcontroller.core.INetMapStorage;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070024import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070025import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Brian O'Connor8c166a72013-11-14 18:41:48 -080026import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
Pavlin Radoslavovc0862662013-12-10 15:31:49 -080027import net.onrc.onos.ofcontroller.forwarding.IForwardingService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070028import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -070029import net.onrc.onos.ofcontroller.util.*;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080030import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
31
32import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033
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;
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080051 protected IForwardingService forwardingService;
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -080052
53 private KryoFactory kryoFactory = new KryoFactory();
54
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000055 // Flow Entry ID generation state
56 private static Random randomGenerator = new Random();
57 private static int nextFlowEntryIdPrefix = 0;
58 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000059
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080060 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070061 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080063 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080064 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
65 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080066 FlowDatabaseWriter flowDatabaseWriter;
67
admin944ef4f2013-10-08 17:48:37 -070068 /**
69 * Initialize the Flow Manager.
70 *
71 * @param conf the Graph Database configuration string.
72 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080073 @Override
74 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080075 dbHandlerApi = new GraphDBOperation(conf);
76 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077 }
78
admin944ef4f2013-10-08 17:48:37 -070079 /**
80 * Shutdown the Flow Manager operation.
81 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080082 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070083 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080084 }
85
admin944ef4f2013-10-08 17:48:37 -070086 /**
87 * Shutdown the Flow Manager operation.
88 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080089 @Override
90 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070091 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080092 dbHandlerApi.close();
93 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080094 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080095
admin944ef4f2013-10-08 17:48:37 -070096 /**
97 * Get the collection of offered module services.
98 *
99 * @return the collection of offered module services.
100 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800101 @Override
102 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
103 Collection<Class<? extends IFloodlightService>> l =
104 new ArrayList<Class<? extends IFloodlightService>>();
105 l.add(IFlowService.class);
106 return l;
107 }
108
admin944ef4f2013-10-08 17:48:37 -0700109 /**
110 * Get the collection of implemented services.
111 *
112 * @return the collection of implemented services.
113 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800114 @Override
115 public Map<Class<? extends IFloodlightService>, IFloodlightService>
116 getServiceImpls() {
117 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700118 IFloodlightService> m =
119 new HashMap<Class<? extends IFloodlightService>,
120 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800121 m.put(IFlowService.class, this);
122 return m;
123 }
124
admin944ef4f2013-10-08 17:48:37 -0700125 /**
126 * Get the collection of modules this module depends on.
127 *
128 * @return the collection of modules this module depends on.
129 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800130 @Override
131 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700132 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800133 Collection<Class<? extends IFloodlightService>> l =
134 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800135 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700136 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700137 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800138 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800139 l.add(IFlowPusherService.class);
140 l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800141 return l;
142 }
143
admin944ef4f2013-10-08 17:48:37 -0700144 /**
145 * Initialize the module.
146 *
147 * @param context the module context to use for the initialization.
148 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800149 @Override
150 public void init(FloodlightModuleContext context)
151 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700152 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800153 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700154 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800155 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800156 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800157 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800158
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700159 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800160 }
161
admin944ef4f2013-10-08 17:48:37 -0700162 /**
163 * Get the next Flow Entry ID to use.
164 *
165 * @return the next Flow Entry ID to use.
166 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800167 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700168 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000169 //
170 // Generate the next Flow Entry ID.
171 // NOTE: For now, the higher 32 bits are random, and
172 // the lower 32 bits are sequential.
173 // In the future, we need a better allocation mechanism.
174 //
175 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
176 nextFlowEntryIdPrefix = randomGenerator.nextInt();
177 nextFlowEntryIdSuffix = 0;
178 } else {
179 nextFlowEntryIdSuffix++;
180 }
181 long result = (long)nextFlowEntryIdPrefix << 32;
182 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
183 return result;
184 }
185
admin944ef4f2013-10-08 17:48:37 -0700186 /**
187 * Startup module operation.
188 *
189 * @param context the module context to use for the startup.
190 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800191 @Override
192 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700193 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700194
admin944ef4f2013-10-08 17:48:37 -0700195 // Initialize the Flow Entry ID generator
196 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800197
198 //
199 // The thread to write to the database
200 //
201 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800202 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800203 flowDatabaseWriter.start();
204
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700205 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800206 // The Flow Event Handler thread:
207 // - create
208 // - register with the Datagrid Service
209 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700210 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700211 flowEventHandler = new FlowEventHandler(this, datagridService);
212 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700213 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800214 }
215
216 /**
217 * Add a flow.
218 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800219 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800220 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800221 */
222 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800223 public FlowId addFlow(FlowPath flowPath) {
224
225 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800226 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800227 long id = getNextFlowEntryId();
228 flowPath.setFlowId(new FlowId(id));
229 }
230
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700231 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700232 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700233 // in case the application didn't do it.
234 //
235 for (FlowEntry flowEntry : flowPath.flowEntries()) {
236 if (flowEntry.flowEntrySwitchState() ==
237 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
238 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
239 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700240 if (! flowEntry.isValidFlowId())
241 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700242 }
243
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800244 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700245 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800246 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700247 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800248 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800249 }
250
251 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000252 * Delete all previously added flows.
253 *
254 * @return true on success, otherwise false.
255 */
256 @Override
257 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800258 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700259 datagridService.notificationSendAllFlowsRemoved();
260 return true;
261 }
262 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000263 }
264
265 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800266 * Delete a previously added flow.
267 *
268 * @param flowId the Flow ID of the flow to delete.
269 * @return true on success, otherwise false.
270 */
271 @Override
272 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800273 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700274 datagridService.notificationSendFlowRemoved(flowId);
275 return true;
276 }
277 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700278 }
279
280 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800281 * Get a previously added flow.
282 *
283 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800284 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800285 */
286 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800287 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800288 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700289 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800290
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700291 /**
292 * Get all installed flows by all installers.
293 *
294 * @return the Flow Paths if found, otherwise null.
295 */
296 @Override
297 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800298 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800299 }
300
301 /**
admin944ef4f2013-10-08 17:48:37 -0700302 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700303 *
admin944ef4f2013-10-08 17:48:37 -0700304 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700305 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700306 * @return the Flow Paths if found, otherwise null.
307 */
308 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800309 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
310 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800311 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
312 SortedMap<Long, FlowPath> sortedFlowPaths =
313 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800314
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800315 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800316 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800317 //
318 for (FlowPath flowPath : sortedFlowPaths.values()) {
319 //
320 // TODO: Add only the Flow Paths that have been successfully
321 // installed.
322 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800323 flowPath.setFlowEntryMatch(null);
324 flowPath.setFlowEntryActions(null);
325 for (FlowEntry flowEntry : flowPath.flowEntries()) {
326 flowEntry.setFlowEntryMatch(null);
327 flowEntry.setFlowEntryActions(null);
328 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800329 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800330 }
331
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800332 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700333 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700334
335 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800336 * Get the collection of my switches.
337 *
338 * @return the collection of my switches.
339 */
340 public Map<Long, IOFSwitch> getMySwitches() {
341 return floodlightProvider.getSwitches();
342 }
343
344 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800345 * Get the network topology.
346 *
347 * @return the network topology.
348 */
349 public Topology getTopology() {
350 return flowEventHandler.getTopology();
351 }
352
353 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800354 * Inform the Flow Manager that a Flow Entry on switch expired.
355 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800356 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800357 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
358 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800359 public void flowEntryOnSwitchExpired(IOFSwitch sw,
360 FlowEntryId flowEntryId) {
361 // Find the Flow Entry
362 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
363 if (flowEntryId == null)
364 return; // Flow Entry not found
365
366 // Find the Flow Path
367 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
368 if (flowPath == null)
369 return; // Flow Path not found
370
371 //
372 // Remove the Flow if the Flow Entry expired on the first switch
373 //
374 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
375 if (srcDpid.value() != sw.getId())
376 return;
377 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800378 }
379
380 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800381 * Inform the Flow Manager that a collection of Flow Entries have been
382 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800383 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800384 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
385 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800386 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800387 public void flowEntriesPushedToSwitch(
388 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800389
390 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800391 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800392 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800393 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800394 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800395
396 //
397 // Mark the Flow Entry that it has been pushed to the switch
398 //
399 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
400
401 //
402 // Write the Flow Entry to the Datagrid
403 //
404 switch (flowEntry.flowEntryUserState()) {
405 case FE_USER_ADD:
406 datagridService.notificationSendFlowEntryAdded(flowEntry);
407 break;
408 case FE_USER_MODIFY:
409 datagridService.notificationSendFlowEntryUpdated(flowEntry);
410 break;
411 case FE_USER_DELETE:
412 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
413 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800414 case FE_USER_UNKNOWN:
415 assert(false);
416 break;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800417 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800418 }
419 }
420
421 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800422 * Generate a notification that a collection of Flow Paths has been
423 * installed in the network.
424 *
425 * @param flowPaths the collection of installed Flow Paths.
426 */
427 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
428 forwardingService.flowsInstalled(flowPaths);
429 }
430
431 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800432 * Push modified Flow-related state as appropriate.
433 *
434 * @param modifiedFlowPaths the collection of modified Flow Paths.
435 * @param modifiedFlowEntries the collection of modified Flow Entries.
436 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800437 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
438 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800439 //
440 // Push the modified Flow state:
441 // - Flow Entries to switches and the datagrid
442 // - Flow Paths to the database
443 //
444 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800445 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800446 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800447 }
448
449 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800450 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700451 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800452 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700453 * are pushed.
454 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800455 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700456 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800457 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800458 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800459 if (modifiedFlowEntries.isEmpty())
460 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700461
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800462 List<Pair<IOFSwitch, FlowEntry>> entries =
463 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
464
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800465 Map<Long, IOFSwitch> mySwitches = getMySwitches();
466
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800467 //
468 // Create a collection of my Flow Entries to push
469 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800470 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800471 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
472 if (mySwitch == null)
473 continue;
474
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800475 //
476 // Assign Flow Entry IDs if missing.
477 //
478 // NOTE: This is an additional safeguard, in case the
479 // mySwitches set has changed (after the Flow Entry IDs
480 // assignments by the caller).
481 //
482 if (! flowEntry.isValidFlowEntryId()) {
483 long id = getNextFlowEntryId();
484 flowEntry.setFlowEntryId(new FlowEntryId(id));
485 }
486
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800487 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800488 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800489 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800490
491 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800492 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700493
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800494 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800495 * Cleanup deleted Flow Entries from the datagrid.
496 *
497 * NOTE: We cleanup only the Flow Entries that are not for our switches.
498 * This is needed to handle the case a switch going down:
499 * It has no Master controller instance, hence no controller instance
500 * will cleanup its flow entries.
501 * This is sub-optimal: we need to elect a controller instance to handle
502 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800503 *
504 * @param modifiedFlowEntries the collection of modified Flow Entries.
505 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800506 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800507 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800508 if (modifiedFlowEntries.isEmpty())
509 return;
510
511 Map<Long, IOFSwitch> mySwitches = getMySwitches();
512
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800513 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800514 //
515 // Process only Flow Entries that should be deleted and have
516 // a valid Flow Entry ID.
517 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800518 if (! flowEntry.isValidFlowEntryId())
519 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800520 if (flowEntry.flowEntryUserState() !=
521 FlowEntryUserState.FE_USER_DELETE) {
522 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800523 }
524
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800525 //
526 // NOTE: The deletion of Flow Entries for my switches is handled
527 // elsewhere.
528 //
529 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
530 if (mySwitch != null)
531 continue;
532
533 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
534
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800535 //
536 // Write the Flow Entry to the Datagrid
537 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800538 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800539 }
540 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700541
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800542 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800543 * Class to implement writing to the database in a separate thread.
544 */
545 class FlowDatabaseWriter extends Thread {
546 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800547 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800548
549 /**
550 * Constructor.
551 *
552 * @param flowManager the Flow Manager to use.
553 * @param blockingQueue the blocking queue to use.
554 */
555 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800556 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800557 this.flowManager = flowManager;
558 this.blockingQueue = blockingQueue;
559 }
560
561 /**
562 * Run the thread.
563 */
564 @Override
565 public void run() {
566 //
567 // The main loop
568 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800569 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800570 try {
571 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800572 FlowPath flowPath = blockingQueue.take();
573 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800574 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800575 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800576 collection.clear();
577 }
578 } catch (Exception exception) {
579 log.debug("Exception writing to the Database: ", exception);
580 }
581 }
582 }
583
584 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800585 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800586 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800587 * NOTE: The complete Flow Paths are pushed only on the instance
588 * responsible for the first switch. This is to avoid database errors
589 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800590 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800591 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800592 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800593 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800594 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavovda8d7232013-12-12 12:48:14 -0800595 List<FlowPath> copiedFlowPaths = new LinkedList<FlowPath>();
596
597 //
598 // Create a copy of the Flow Paths to push, because the pushing
599 // itself will happen on a separate thread.
600 //
601 Kryo kryo = kryoFactory.newKryo();
602 for (FlowPath flowPath : modifiedFlowPaths) {
603 FlowPath copyFlowPath = kryo.copy(flowPath);
604 copiedFlowPaths.add(copyFlowPath);
605 }
606 kryoFactory.deleteKryo(kryo);
607
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 Radoslavovda8d7232013-12-12 12:48:14 -0800612 flowPathsToDatabaseQueue.addAll(copiedFlowPaths);
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 Radoslavov9f33edb2013-11-06 18:24:37 -0800629 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700630
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800631 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800632 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800633 // Push the changes only on the instance responsible for the
634 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800635 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800636 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
637 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
638 if (mySrcSwitch == null)
639 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800640
641 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800642 // Delete the Flow Path from the Network Map
643 //
644 if (flowPath.flowPathUserState() ==
645 FlowPathUserState.FP_USER_DELETE) {
646 log.debug("Deleting Flow Path From Database: {}",
647 flowPath.toString());
648
649 try {
650 if (! FlowDatabaseOperation.deleteFlow(
651 dbHandlerInner,
652 flowPath.flowId())) {
653 log.error("Cannot delete Flow Path {} from Network Map",
654 flowPath.flowId());
655 }
656 } catch (Exception e) {
657 log.error("Exception deleting Flow Path from Network MAP: {}", e);
658 }
659 continue;
660 }
661
662 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800663 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800664 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800665 boolean allValid = true;
666 for (FlowEntry flowEntry : flowPath.flowEntries()) {
667 if (flowEntry.flowEntryUserState() ==
668 FlowEntryUserState.FE_USER_DELETE) {
669 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700670 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800671 if (! flowEntry.isValidFlowEntryId()) {
672 allValid = false;
673 break;
674 }
675 }
676 if (! allValid)
677 continue;
678
679 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
680
681 //
682 // Write the Flow Path to the Network Map
683 //
684 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800685 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800686 String logMsg = "Cannot write to Network Map Flow Path " +
687 flowPath.flowId();
688 log.error(logMsg);
689 }
690 } catch (Exception e) {
691 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700692 }
693 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700694 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800695}