blob: bd498cc85e953951a4bafa796b9fbbc6229525b8 [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;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080048
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000049 // Flow Entry ID generation state
50 private static Random randomGenerator = new Random();
51 private static int nextFlowEntryIdPrefix = 0;
52 private static int nextFlowEntryIdSuffix = 0;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000053
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080054 /** The logger. */
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070055 private final static Logger log = LoggerFactory.getLogger(FlowManager.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080057 // The queue to write Flow Entries to the database
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080058 private BlockingQueue<FlowPath> flowPathsToDatabaseQueue =
59 new LinkedBlockingQueue<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -080060 FlowDatabaseWriter flowDatabaseWriter;
61
admin944ef4f2013-10-08 17:48:37 -070062 /**
63 * Initialize the Flow Manager.
64 *
65 * @param conf the Graph Database configuration string.
66 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080067 @Override
68 public void init(String conf) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080069 dbHandlerApi = new GraphDBOperation(conf);
70 dbHandlerInner = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071 }
72
admin944ef4f2013-10-08 17:48:37 -070073 /**
74 * Shutdown the Flow Manager operation.
75 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080076 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -070077 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078 }
79
admin944ef4f2013-10-08 17:48:37 -070080 /**
81 * Shutdown the Flow Manager operation.
82 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080083 @Override
84 public void close() {
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070085 datagridService.deregisterFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -080086 dbHandlerApi.close();
87 dbHandlerInner.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080088 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080089
admin944ef4f2013-10-08 17:48:37 -070090 /**
91 * Get the collection of offered module services.
92 *
93 * @return the collection of offered module services.
94 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080095 @Override
96 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
97 Collection<Class<? extends IFloodlightService>> l =
98 new ArrayList<Class<? extends IFloodlightService>>();
99 l.add(IFlowService.class);
100 return l;
101 }
102
admin944ef4f2013-10-08 17:48:37 -0700103 /**
104 * Get the collection of implemented services.
105 *
106 * @return the collection of implemented services.
107 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800108 @Override
109 public Map<Class<? extends IFloodlightService>, IFloodlightService>
110 getServiceImpls() {
111 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700112 IFloodlightService> m =
113 new HashMap<Class<? extends IFloodlightService>,
114 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800115 m.put(IFlowService.class, this);
116 return m;
117 }
118
admin944ef4f2013-10-08 17:48:37 -0700119 /**
120 * Get the collection of modules this module depends on.
121 *
122 * @return the collection of modules this module depends on.
123 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800124 @Override
125 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700126 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800127 Collection<Class<? extends IFloodlightService>> l =
128 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800129 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700130 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700131 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800132 l.add(IRestApiService.class);
Pavlin Radoslavovc0862662013-12-10 15:31:49 -0800133 l.add(IFlowPusherService.class);
134 l.add(IForwardingService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800135 return l;
136 }
137
admin944ef4f2013-10-08 17:48:37 -0700138 /**
139 * Initialize the module.
140 *
141 * @param context the module context to use for the initialization.
142 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800143 @Override
144 public void init(FloodlightModuleContext context)
145 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700146 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800147 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700148 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800149 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov939ca6b2013-12-03 12:35:37 -0800150 pusher = context.getServiceImpl(IFlowPusherService.class);
Brian O'Connor8c166a72013-11-14 18:41:48 -0800151
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700152 this.init("");
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800153 }
154
admin944ef4f2013-10-08 17:48:37 -0700155 /**
156 * Get the next Flow Entry ID to use.
157 *
158 * @return the next Flow Entry ID to use.
159 */
Naoki Shiota4e77de92013-11-18 17:29:54 -0800160 @Override
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700161 public synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000162 //
163 // Generate the next Flow Entry ID.
164 // NOTE: For now, the higher 32 bits are random, and
165 // the lower 32 bits are sequential.
166 // In the future, we need a better allocation mechanism.
167 //
168 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
169 nextFlowEntryIdPrefix = randomGenerator.nextInt();
170 nextFlowEntryIdSuffix = 0;
171 } else {
172 nextFlowEntryIdSuffix++;
173 }
174 long result = (long)nextFlowEntryIdPrefix << 32;
175 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
176 return result;
177 }
178
admin944ef4f2013-10-08 17:48:37 -0700179 /**
180 * Startup module operation.
181 *
182 * @param context the module context to use for the startup.
183 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800184 @Override
185 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700186 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700187
admin944ef4f2013-10-08 17:48:37 -0700188 // Initialize the Flow Entry ID generator
189 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800190
191 //
192 // The thread to write to the database
193 //
194 flowDatabaseWriter = new FlowDatabaseWriter(this,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800195 flowPathsToDatabaseQueue);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800196 flowDatabaseWriter.start();
197
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700198 //
Pavlin Radoslavovc9da5322013-11-22 11:59:46 -0800199 // The Flow Event Handler thread:
200 // - create
201 // - register with the Datagrid Service
202 // - startup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700203 //
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700204 flowEventHandler = new FlowEventHandler(this, datagridService);
205 datagridService.registerFlowEventHandlerService(flowEventHandler);
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700206 flowEventHandler.start();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800207 }
208
209 /**
210 * Add a flow.
211 *
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800212 * @param flowPath the Flow Path to install.
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800213 * @return the Flow ID on success, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800214 */
215 @Override
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800216 public FlowId addFlow(FlowPath flowPath) {
217
218 // Allocate the Flow ID if necessary
Pavlin Radoslavov892dd182013-12-05 23:33:15 -0800219 if (! flowPath.isValidFlowId()) {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800220 long id = getNextFlowEntryId();
221 flowPath.setFlowId(new FlowId(id));
222 }
223
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700224 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700225 // NOTE: We need to explicitly initialize some of the state,
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700226 // in case the application didn't do it.
227 //
228 for (FlowEntry flowEntry : flowPath.flowEntries()) {
229 if (flowEntry.flowEntrySwitchState() ==
230 FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
231 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
232 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700233 if (! flowEntry.isValidFlowId())
234 flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700235 }
236
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800237 if (FlowDatabaseOperation.addFlow(dbHandlerApi, flowPath)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700238 datagridService.notificationSendFlowAdded(flowPath);
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800239 return flowPath.flowId();
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700240 }
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800241 return null;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800242 }
243
244 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000245 * Delete all previously added flows.
246 *
247 * @return true on success, otherwise false.
248 */
249 @Override
250 public boolean deleteAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800251 if (FlowDatabaseOperation.deleteAllFlows(dbHandlerApi)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700252 datagridService.notificationSendAllFlowsRemoved();
253 return true;
254 }
255 return false;
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000256 }
257
258 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800259 * Delete a previously added flow.
260 *
261 * @param flowId the Flow ID of the flow to delete.
262 * @return true on success, otherwise false.
263 */
264 @Override
265 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800266 if (FlowDatabaseOperation.deleteFlow(dbHandlerApi, flowId)) {
Pavlin Radoslavov1308dc62013-10-25 15:54:31 -0700267 datagridService.notificationSendFlowRemoved(flowId);
268 return true;
269 }
270 return false;
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700271 }
272
273 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800274 * Get a previously added flow.
275 *
276 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800277 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800278 */
279 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800280 public FlowPath getFlow(FlowId flowId) {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800281 return FlowDatabaseOperation.getFlow(dbHandlerApi, flowId);
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700282 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800283
Pavlin Radoslavov661c86f2013-10-21 12:40:40 -0700284 /**
285 * Get all installed flows by all installers.
286 *
287 * @return the Flow Paths if found, otherwise null.
288 */
289 @Override
290 public ArrayList<FlowPath> getAllFlows() {
Pavlin Radoslavovbc96ae12013-11-05 08:44:02 -0800291 return FlowDatabaseOperation.getAllFlows(dbHandlerApi);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800292 }
293
294 /**
admin944ef4f2013-10-08 17:48:37 -0700295 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700296 *
admin944ef4f2013-10-08 17:48:37 -0700297 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -0700298 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700299 * @return the Flow Paths if found, otherwise null.
300 */
301 @Override
Pavlin Radoslavov4ef6ba22013-11-22 19:32:58 -0800302 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId,
303 int maxFlows) {
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800304 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
305 SortedMap<Long, FlowPath> sortedFlowPaths =
306 flowEventHandler.getAllFlowPathsCopy();
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800307
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800308 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800309 // Truncate each Flow Path and Flow Entry
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800310 //
311 for (FlowPath flowPath : sortedFlowPaths.values()) {
312 //
313 // TODO: Add only the Flow Paths that have been successfully
314 // installed.
315 //
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800316 flowPath.setFlowEntryMatch(null);
317 flowPath.setFlowEntryActions(null);
318 for (FlowEntry flowEntry : flowPath.flowEntries()) {
319 flowEntry.setFlowEntryMatch(null);
320 flowEntry.setFlowEntryActions(null);
321 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800322 flowPaths.add(flowPath);
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800323 }
324
Pavlin Radoslavove79c19a2013-12-06 09:28:15 -0800325 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700326 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700327
328 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800329 * Get the collection of my switches.
330 *
331 * @return the collection of my switches.
332 */
333 public Map<Long, IOFSwitch> getMySwitches() {
334 return floodlightProvider.getSwitches();
335 }
336
337 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800338 * Get the network topology.
339 *
340 * @return the network topology.
341 */
342 public Topology getTopology() {
343 return flowEventHandler.getTopology();
344 }
345
346 /**
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800347 * Inform the Flow Manager that a Flow Entry on switch expired.
348 *
Pavlin Radoslavov3bd5ccf2013-11-26 15:10:21 -0800349 * @param sw the switch the Flow Entry expired on.
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800350 * @param flowEntryId the Flow Entry ID of the expired Flow Entry.
351 */
Pavlin Radoslavovc5718e72013-12-10 15:47:10 -0800352 public void flowEntryOnSwitchExpired(IOFSwitch sw,
353 FlowEntryId flowEntryId) {
354 // Find the Flow Entry
355 FlowEntry flowEntry = datagridService.getFlowEntry(flowEntryId);
356 if (flowEntryId == null)
357 return; // Flow Entry not found
358
359 // Find the Flow Path
360 FlowPath flowPath = datagridService.getFlow(flowEntry.flowId());
361 if (flowPath == null)
362 return; // Flow Path not found
363
364 //
365 // Remove the Flow if the Flow Entry expired on the first switch
366 //
367 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
368 if (srcDpid.value() != sw.getId())
369 return;
370 deleteFlow(flowPath.flowId());
Pavlin Radoslavov4df85ae2013-11-26 14:48:32 -0800371 }
372
373 /**
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800374 * Inform the Flow Manager that a collection of Flow Entries have been
375 * pushed to a switch.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800376 *
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800377 * @param entries the collection of <IOFSwitch, FlowEntry> pairs
378 * that have been pushed.
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800379 */
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800380 public void flowEntriesPushedToSwitch(
381 Collection<Pair<IOFSwitch, FlowEntry>> entries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800382
383 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800384 // Process all entries
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800385 //
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800386 for (Pair<IOFSwitch, FlowEntry> entry : entries) {
Pavlin Radoslavov4535bc12013-12-05 10:43:49 -0800387 FlowEntry flowEntry = entry.second;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800388
389 //
390 // Mark the Flow Entry that it has been pushed to the switch
391 //
392 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
393
394 //
395 // Write the Flow Entry to the Datagrid
396 //
397 switch (flowEntry.flowEntryUserState()) {
398 case FE_USER_ADD:
399 datagridService.notificationSendFlowEntryAdded(flowEntry);
400 break;
401 case FE_USER_MODIFY:
402 datagridService.notificationSendFlowEntryUpdated(flowEntry);
403 break;
404 case FE_USER_DELETE:
405 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
406 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800407 case FE_USER_UNKNOWN:
408 assert(false);
409 break;
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800410 }
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800411 }
412 }
413
414 /**
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800415 * Push modified Flow-related state as appropriate.
416 *
417 * @param modifiedFlowPaths the collection of modified Flow Paths.
418 * @param modifiedFlowEntries the collection of modified Flow Entries.
419 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800420 void pushModifiedFlowState(Collection<FlowPath> modifiedFlowPaths,
421 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800422 //
423 // Push the modified Flow state:
424 // - Flow Entries to switches and the datagrid
425 // - Flow Paths to the database
426 //
427 pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800428 pushModifiedFlowPathsToDatabase(modifiedFlowPaths);
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800429 cleanupDeletedFlowEntriesFromDatagrid(modifiedFlowEntries);
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800430 }
431
432 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800433 * Push modified Flow Entries to switches.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700434 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 * NOTE: Only the Flow Entries to switches controlled by this instance
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700436 * are pushed.
437 *
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800438 * @param modifiedFlowEntries the collection of modified Flow Entries.
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700439 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800440 private void pushModifiedFlowEntriesToSwitches(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800441 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800442 if (modifiedFlowEntries.isEmpty())
443 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700444
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800445 List<Pair<IOFSwitch, FlowEntry>> entries =
446 new LinkedList<Pair<IOFSwitch, FlowEntry>>();
447
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800448 Map<Long, IOFSwitch> mySwitches = getMySwitches();
449
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800450 //
451 // Create a collection of my Flow Entries to push
452 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800453 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800454 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
455 if (mySwitch == null)
456 continue;
457
Pavlin Radoslavovaca49d12013-12-04 19:49:17 -0800458 //
459 // Assign Flow Entry IDs if missing.
460 //
461 // NOTE: This is an additional safeguard, in case the
462 // mySwitches set has changed (after the Flow Entry IDs
463 // assignments by the caller).
464 //
465 if (! flowEntry.isValidFlowEntryId()) {
466 long id = getNextFlowEntryId();
467 flowEntry.setFlowEntryId(new FlowEntryId(id));
468 }
469
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800470 log.debug("Pushing Flow Entry To Switch: {}", flowEntry.toString());
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800471 entries.add(new Pair<IOFSwitch, FlowEntry>(mySwitch, flowEntry));
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800472 }
Pavlin Radoslavovab3f8862013-12-04 18:35:53 -0800473
474 pusher.pushFlowEntries(entries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800475 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700476
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800477 /**
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800478 * Cleanup deleted Flow Entries from the datagrid.
479 *
480 * NOTE: We cleanup only the Flow Entries that are not for our switches.
481 * This is needed to handle the case a switch going down:
482 * It has no Master controller instance, hence no controller instance
483 * will cleanup its flow entries.
484 * This is sub-optimal: we need to elect a controller instance to handle
485 * the cleanup of such orphaned flow entries.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800486 *
487 * @param modifiedFlowEntries the collection of modified Flow Entries.
488 */
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800489 private void cleanupDeletedFlowEntriesFromDatagrid(
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800490 Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800491 if (modifiedFlowEntries.isEmpty())
492 return;
493
494 Map<Long, IOFSwitch> mySwitches = getMySwitches();
495
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800496 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800497 //
498 // Process only Flow Entries that should be deleted and have
499 // a valid Flow Entry ID.
500 //
Pavlin Radoslavov426a8532013-12-02 17:32:21 -0800501 if (! flowEntry.isValidFlowEntryId())
502 continue;
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800503 if (flowEntry.flowEntryUserState() !=
504 FlowEntryUserState.FE_USER_DELETE) {
505 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800506 }
507
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800508 //
509 // NOTE: The deletion of Flow Entries for my switches is handled
510 // elsewhere.
511 //
512 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
513 if (mySwitch != null)
514 continue;
515
516 log.debug("Pushing cleanup of Flow Entry To Datagrid: {}", flowEntry.toString());
517
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800518 //
519 // Write the Flow Entry to the Datagrid
520 //
Pavlin Radoslavovda0ab442013-12-04 14:08:58 -0800521 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800522 }
523 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700524
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800525 /**
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800526 * Class to implement writing to the database in a separate thread.
527 */
528 class FlowDatabaseWriter extends Thread {
529 private FlowManager flowManager;
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800530 private BlockingQueue<FlowPath> blockingQueue;
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800531
532 /**
533 * Constructor.
534 *
535 * @param flowManager the Flow Manager to use.
536 * @param blockingQueue the blocking queue to use.
537 */
538 FlowDatabaseWriter(FlowManager flowManager,
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800539 BlockingQueue<FlowPath> blockingQueue) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800540 this.flowManager = flowManager;
541 this.blockingQueue = blockingQueue;
542 }
543
544 /**
545 * Run the thread.
546 */
547 @Override
548 public void run() {
549 //
550 // The main loop
551 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800552 Collection<FlowPath> collection = new LinkedList<FlowPath>();
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800553 try {
554 while (true) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800555 FlowPath flowPath = blockingQueue.take();
556 collection.add(flowPath);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800557 blockingQueue.drainTo(collection);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800558 flowManager.writeModifiedFlowPathsToDatabase(collection);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800559 collection.clear();
560 }
561 } catch (Exception exception) {
562 log.debug("Exception writing to the Database: ", exception);
563 }
564 }
565 }
566
567 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800568 * Push Flow Paths to the Network MAP.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800569 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800570 * NOTE: The complete Flow Paths are pushed only on the instance
571 * responsible for the first switch. This is to avoid database errors
572 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800573 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800574 * @param modifiedFlowPaths the collection of Flow Paths to push.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800575 */
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800576 private void pushModifiedFlowPathsToDatabase(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800577 Collection<FlowPath> modifiedFlowPaths) {
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800578 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800579 // We only add the Flow Paths to the Database Queue.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800580 // The FlowDatabaseWriter thread is responsible for the actual writing.
581 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800582 flowPathsToDatabaseQueue.addAll(modifiedFlowPaths);
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800583 }
584
585 /**
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800586 * Write Flow Paths to the Network MAP.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800587 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800588 * NOTE: The complete Flow Paths are pushed only on the instance
589 * responsible for the first switch. This is to avoid database errors
590 * when multiple instances are writing Flow Entries for the same Flow Path.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800591 *
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800592 * @param modifiedFlowPaths the collection of Flow Paths to write.
Pavlin Radoslavov584bd112013-11-21 20:59:33 -0800593 */
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800594 private void writeModifiedFlowPathsToDatabase(
595 Collection<FlowPath> modifiedFlowPaths) {
596 if (modifiedFlowPaths.isEmpty())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800597 return;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700598
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800599 Map<Long, IOFSwitch> mySwitches = getMySwitches();
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700600
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800601 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800602 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800603 // Push the changes only on the instance responsible for the
604 // first switch.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800605 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800606 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
607 IOFSwitch mySrcSwitch = mySwitches.get(srcDpid.value());
608 if (mySrcSwitch == null)
609 continue;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800610
611 //
Pavlin Radoslavovef545052013-12-05 15:17:25 -0800612 // Delete the Flow Path from the Network Map
613 //
614 if (flowPath.flowPathUserState() ==
615 FlowPathUserState.FP_USER_DELETE) {
616 log.debug("Deleting Flow Path From Database: {}",
617 flowPath.toString());
618
619 try {
620 if (! FlowDatabaseOperation.deleteFlow(
621 dbHandlerInner,
622 flowPath.flowId())) {
623 log.error("Cannot delete Flow Path {} from Network Map",
624 flowPath.flowId());
625 }
626 } catch (Exception e) {
627 log.error("Exception deleting Flow Path from Network MAP: {}", e);
628 }
629 continue;
630 }
631
632 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800633 // Test whether all Flow Entries are valid
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800634 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800635 boolean allValid = true;
636 for (FlowEntry flowEntry : flowPath.flowEntries()) {
637 if (flowEntry.flowEntryUserState() ==
638 FlowEntryUserState.FE_USER_DELETE) {
639 continue;
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700640 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800641 if (! flowEntry.isValidFlowEntryId()) {
642 allValid = false;
643 break;
644 }
645 }
646 if (! allValid)
647 continue;
648
649 log.debug("Pushing Flow Path To Database: {}", flowPath.toString());
650
651 //
652 // Write the Flow Path to the Network Map
653 //
654 try {
Pavlin Radoslavov051abb42013-12-05 17:24:50 -0800655 if (! FlowDatabaseOperation.addFlow(dbHandlerInner, flowPath)) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800656 String logMsg = "Cannot write to Network Map Flow Path " +
657 flowPath.flowId();
658 log.error(logMsg);
659 }
660 } catch (Exception e) {
661 log.error("Exception writing Flow Path to Network MAP: ", e);
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700662 }
663 }
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700664 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800665}