blob: 41cf67030d62f2a0b5e329274899e91bde42ad86 [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 Radoslavovb6f53542013-03-01 16:02:14 -080030
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
admin944ef4f2013-10-08 17:48:37 -070034/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070035 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070036 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070037public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080038 protected GraphDBOperation dbHandlerApi;
39 protected GraphDBOperation dbHandlerInner;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080040
Jonathan Hart50a94982013-04-10 14:49:51 -070041 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070042 protected volatile IDatagridService datagridService;
43 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070044 protected FloodlightModuleContext context;
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070045 protected FlowEventHandler flowEventHandler;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046
Brian O'Connor8c166a72013-11-14 18:41:48 -080047 protected IFlowPusherService pusher;
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080048 protected IForwardingService forwardingService;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080049
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000050 // Flow Entry ID generation state
51 private static Random randomGenerator = new Random();
52 private static int nextFlowEntryIdPrefix = 0;
53 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000054
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080055 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070056 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080058 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080059 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
60 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080061 FlowDatabaseWriter flowDatabaseWriter;
62
admin944ef4f2013-10-08 17:48:37 -070063 /**
64 * Initialize the Flow Manager.
65 *
66 * @param conf the Graph Database configuration string.
67 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068 @Override
69 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080070 dbHandlerApi = new GraphDBOperation(conf);
71 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 }
73
admin944ef4f2013-10-08 17:48:37 -070074 /**
75 * Shutdown the Flow Manager operation.
76 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070078 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080079 }
80
admin944ef4f2013-10-08 17:48:37 -070081 /**
82 * Shutdown the Flow Manager operation.
83 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080084 @Override
85 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070086 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080087 dbHandlerApi.close();
88 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080089 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080090
admin944ef4f2013-10-08 17:48:37 -070091 /**
92 * Get the collection of offered module services.
93 *
94 * @return the collection of offered module services.
95 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080096 @Override
97 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
98 Collection<Class<? extends IFloodlightService>> l =
99 new ArrayList<Class<? extends IFloodlightService>>();
100 l.add(IFlowService.class);
101 return l;
102 }
103
admin944ef4f2013-10-08 17:48:37 -0700104 /**
105 * Get the collection of implemented services.
106 *
107 * @return the collection of implemented services.
108 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800109 @Override
110 public Map<Class<? extends IFloodlightService>, IFloodlightService>
111 getServiceImpls() {
112 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700113 IFloodlightService> m =
114 new HashMap<Class<? extends IFloodlightService>,
115 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800116 m.put(IFlowService.class, this);
117 return m;
118 }
119
admin944ef4f2013-10-08 17:48:37 -0700120 /**
121 * Get the collection of modules this module depends on.
122 *
123 * @return the collection of modules this module depends on.
124 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800125 @Override
126 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700127 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800128 Collection<Class<? extends IFloodlightService>> l =
129 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800130 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700131 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700132 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800133 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800134 l.add(IFlowPusherService.class);
135 l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800136 return l;
137 }
138
admin944ef4f2013-10-08 17:48:37 -0700139 /**
140 * Initialize the module.
141 *
142 * @param context the module context to use for the initialization.
143 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800144 @Override
145 public void init(FloodlightModuleContext context)
146 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700147 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800148 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700149 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800150 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800151 pusher = context.getServiceImpl(IFlowPusherService.class);
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800152 forwardingService = context.getServiceImpl(IForwardingService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800153
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700154 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800155 }
156
admin944ef4f2013-10-08 17:48:37 -0700157 /**
158 * Get the next Flow Entry ID to use.
159 *
160 * @return the next Flow Entry ID to use.
161 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800162 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700163 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000164 //
165 // Generate the next Flow Entry ID.
166 // NOTE: For now, the higher 32 bits are random, and
167 // the lower 32 bits are sequential.
168 // In the future, we need a better allocation mechanism.
169 //
170 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
171 nextFlowEntryIdPrefix = randomGenerator.nextInt();
172 nextFlowEntryIdSuffix = 0;
173 } else {
174 nextFlowEntryIdSuffix++;
175 }
176 long result = (long)nextFlowEntryIdPrefix << 32;
177 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
178 return result;
179 }
180
admin944ef4f2013-10-08 17:48:37 -0700181 /**
182 * Startup module operation.
183 *
184 * @param context the module context to use for the startup.
185 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800186 @Override
187 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700188 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700189
admin944ef4f2013-10-08 17:48:37 -0700190 // Initialize the Flow Entry ID generator
191 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800192
193 //
194 // The thread to write to the database
195 //
196 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800197 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800198 flowDatabaseWriter.start();
199
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700200 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800201 // The Flow Event Handler thread:
202 // - create
203 // - register with the Datagrid Service
204 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700205 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700206 flowEventHandler = new FlowEventHandler(this, datagridService);
207 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700208 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800209 }
210
211 /**
212 * Add a flow.
213 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800214 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800215 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800216 */
217 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800218 public FlowId addFlow(FlowPath flowPath) {
219
220 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800221 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800222 long id = getNextFlowEntryId();
223 flowPath.setFlowId(new FlowId(id));
224 }
225
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700226 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700227 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700228 // in case the application didn't do it.
229 //
230 for (FlowEntry flowEntry : flowPath.flowEntries()) {
231 if (flowEntry.flowEntrySwitchState() ==
232 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
233 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
234 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700235 if (! flowEntry.isValidFlowId())
236 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700237 }
238
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800239 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700240 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800241 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700242 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800243 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800244 }
245
246 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000247 * Delete all previously added flows.
248 *
249 * @return true on success, otherwise false.
250 */
251 @Override
252 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800253 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700254 datagridService.notificationSendAllFlowsRemoved();
255 return true;
256 }
257 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000258 }
259
260 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800261 * Delete a previously added flow.
262 *
263 * @param flowId the Flow ID of the flow to delete.
264 * @return true on success, otherwise false.
265 */
266 @Override
267 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800268 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700269 datagridService.notificationSendFlowRemoved(flowId);
270 return true;
271 }
272 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700273 }
274
275 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800276 * Get a previously added flow.
277 *
278 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800279 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800280 */
281 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800282 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800283 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700284 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800285
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700286 /**
287 * Get all installed flows by all installers.
288 *
289 * @return the Flow Paths if found, otherwise null.
290 */
291 @Override
292 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800293 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800294 }
295
296 /**
admin944ef4f2013-10-08 17:48:37 -0700297 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700298 *
admin944ef4f2013-10-08 17:48:37 -0700299 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700300 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700301 * @return the Flow Paths if found, otherwise null.
302 */
303 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800304 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
305 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800306 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
307 SortedMap<Long, FlowPath> sortedFlowPaths =
308 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800309
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800310 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800311 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800312 //
313 for (FlowPath flowPath : sortedFlowPaths.values()) {
314 //
315 // TODO: Add only the Flow Paths that have been successfully
316 // installed.
317 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800318 flowPath.setFlowEntryMatch(null);
319 flowPath.setFlowEntryActions(null);
320 for (FlowEntry flowEntry : flowPath.flowEntries()) {
321 flowEntry.setFlowEntryMatch(null);
322 flowEntry.setFlowEntryActions(null);
323 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800324 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800325 }
326
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800327 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700328 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700329
330 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800331 * Get the collection of my switches.
332 *
333 * @return the collection of my switches.
334 */
335 public Map<Long, IOFSwitch> getMySwitches() {
336 return floodlightProvider.getSwitches();
337 }
338
339 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800340 * Get the network topology.
341 *
342 * @return the network topology.
343 */
344 public Topology getTopology() {
345 return flowEventHandler.getTopology();
346 }
347
348 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800349 * Inform the Flow Manager that a Flow Entry on switch expired.
350 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800351 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800352 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
353 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800354 public void flowEntryOnSwitchExpired(IOFSwitch sw,
355 FlowEntryId flowEntryId) {
356 // Find the Flow Entry
357 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
358 if (flowEntryId == null)
359 return; // Flow Entry not found
360
361 // Find the Flow Path
362 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
363 if (flowPath == null)
364 return; // Flow Path not found
365
366 //
367 // Remove the Flow if the Flow Entry expired on the first switch
368 //
369 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
370 if (srcDpid.value() != sw.getId())
371 return;
372 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800373 }
374
375 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800376 * Inform the Flow Manager that a collection of Flow Entries have been
377 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800378 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800379 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
380 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800381 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800382 public void flowEntriesPushedToSwitch(
383 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800384
385 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800386 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800387 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800388 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800389 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800390
391 //
392 // Mark the Flow Entry that it has been pushed to the switch
393 //
394 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
395
396 //
397 // Write the Flow Entry to the Datagrid
398 //
399 switch (flowEntry.flowEntryUserState()) {
400 case FE_USER_ADD:
401 datagridService.notificationSendFlowEntryAdded(flowEntry);
402 break;
403 case FE_USER_MODIFY:
404 datagridService.notificationSendFlowEntryUpdated(flowEntry);
405 break;
406 case FE_USER_DELETE:
407 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
408 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800409 case FE_USER_UNKNOWN:
410 assert(false);
411 break;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800412 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800413 }
414 }
415
416 /**
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800417 * Generate a notification that a collection of Flow Paths has been
418 * installed in the network.
419 *
420 * @param flowPaths the collection of installed Flow Paths.
421 */
422 void notificationFlowPathsInstalled(Collection<FlowPath> flowPaths) {
423 forwardingService.flowsInstalled(flowPaths);
424 }
425
426 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800427 * Push modified Flow-related state as appropriate.
428 *
429 * @param modifiedFlowPaths the collection of modified Flow Paths.
430 * @param modifiedFlowEntries the collection of modified Flow Entries.
431 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800432 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
433 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800434 //
435 // Push the modified Flow state:
436 // - Flow Entries to switches and the datagrid
437 // - Flow Paths to the database
438 //
439 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800440 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800441 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800442 }
443
444 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800445 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700446 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800447 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700448 * are pushed.
449 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800450 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700451 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800452 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800453 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800454 if (modifiedFlowEntries.isEmpty())
455 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700456
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800457 List<Pair<IOFSwitch, FlowEntry>> entries =
458 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
459
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800460 Map<Long, IOFSwitch> mySwitches = getMySwitches();
461
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800462 //
463 // Create a collection of my Flow Entries to push
464 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800465 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800466 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
467 if (mySwitch == null)
468 continue;
469
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800470 //
471 // Assign Flow Entry IDs if missing.
472 //
473 // NOTE: This is an additional safeguard, in case the
474 // mySwitches set has changed (after the Flow Entry IDs
475 // assignments by the caller).
476 //
477 if (! flowEntry.isValidFlowEntryId()) {
478 long id = getNextFlowEntryId();
479 flowEntry.setFlowEntryId(new FlowEntryId(id));
480 }
481
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800482 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800483 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800484 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800485
486 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800487 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700488
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800489 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800490 * Cleanup deleted Flow Entries from the datagrid.
491 *
492 * NOTE: We cleanup only the Flow Entries that are not for our switches.
493 * This is needed to handle the case a switch going down:
494 * It has no Master controller instance, hence no controller instance
495 * will cleanup its flow entries.
496 * This is sub-optimal: we need to elect a controller instance to handle
497 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800498 *
499 * @param modifiedFlowEntries the collection of modified Flow Entries.
500 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800501 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800502 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800503 if (modifiedFlowEntries.isEmpty())
504 return;
505
506 Map<Long, IOFSwitch> mySwitches = getMySwitches();
507
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800508 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800509 //
510 // Process only Flow Entries that should be deleted and have
511 // a valid Flow Entry ID.
512 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800513 if (! flowEntry.isValidFlowEntryId())
514 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800515 if (flowEntry.flowEntryUserState() !=
516 FlowEntryUserState.FE_USER_DELETE) {
517 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800518 }
519
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800520 //
521 // NOTE: The deletion of Flow Entries for my switches is handled
522 // elsewhere.
523 //
524 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
525 if (mySwitch != null)
526 continue;
527
528 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
529
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800530 //
531 // Write the Flow Entry to the Datagrid
532 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800533 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800534 }
535 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700536
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800537 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800538 * Class to implement writing to the database in a separate thread.
539 */
540 class FlowDatabaseWriter extends Thread {
541 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800542 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800543
544 /**
545 * Constructor.
546 *
547 * @param flowManager the Flow Manager to use.
548 * @param blockingQueue the blocking queue to use.
549 */
550 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800551 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800552 this.flowManager = flowManager;
553 this.blockingQueue = blockingQueue;
554 }
555
556 /**
557 * Run the thread.
558 */
559 @Override
560 public void run() {
561 //
562 // The main loop
563 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800564 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800565 try {
566 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800567 FlowPath flowPath = blockingQueue.take();
568 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800569 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800570 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800571 collection.clear();
572 }
573 } catch (Exception exception) {
574 log.debug("Exception writing to the Database: ", exception);
575 }
576 }
577 }
578
579 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800580 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800581 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800582 * NOTE: The complete Flow Paths are pushed only on the instance
583 * responsible for the first switch. This is to avoid database errors
584 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800585 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800586 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800587 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800588 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800589 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800590 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800591 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800592 // The FlowDatabaseWriter thread is responsible for the actual writing.
593 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800594 flowPathsToDatabaseQueue.addAll(modifiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800595 }
596
597 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800598 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800599 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800600 * NOTE: The complete Flow Paths are pushed only on the instance
601 * responsible for the first switch. This is to avoid database errors
602 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800603 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800604 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800605 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800606 private void writeModifiedFlowPathsToDatabase(
607 Collection<FlowPath> modifiedFlowPaths) {
608 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800609 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700610
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800611 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700612
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800613 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800614 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800615 // Push the changes only on the instance responsible for the
616 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800617 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800618 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
619 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
620 if (mySrcSwitch == null)
621 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800622
623 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800624 // Delete the Flow Path from the Network Map
625 //
626 if (flowPath.flowPathUserState() ==
627 FlowPathUserState.FP_USER_DELETE) {
628 log.debug("Deleting Flow Path From Database: {}",
629 flowPath.toString());
630
631 try {
632 if (! FlowDatabaseOperation.deleteFlow(
633 dbHandlerInner,
634 flowPath.flowId())) {
635 log.error("Cannot delete Flow Path {} from Network Map",
636 flowPath.flowId());
637 }
638 } catch (Exception e) {
639 log.error("Exception deleting Flow Path from Network MAP: {}", e);
640 }
641 continue;
642 }
643
644 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800645 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800646 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800647 boolean allValid = true;
648 for (FlowEntry flowEntry : flowPath.flowEntries()) {
649 if (flowEntry.flowEntryUserState() ==
650 FlowEntryUserState.FE_USER_DELETE) {
651 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700652 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800653 if (! flowEntry.isValidFlowEntryId()) {
654 allValid = false;
655 break;
656 }
657 }
658 if (! allValid)
659 continue;
660
661 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
662
663 //
664 // Write the Flow Path to the Network Map
665 //
666 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800667 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800668 String logMsg = "Cannot write to Network Map Flow Path " +
669 flowPath.flowId();
670 log.error(logMsg);
671 }
672 } catch (Exception e) {
673 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700674 }
675 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700676 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800677}