blob: 3538eb44983ee091e7d51a925b3365ecb171fecb [file] [log] [blame]
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
2
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07003import java.util.ArrayList;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07004import java.util.Collection;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07005import java.util.HashMap;
6import java.util.Iterator;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07007import java.util.LinkedList;
8import java.util.List;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07009import java.util.Map;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
11import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.LinkedBlockingQueue;
14
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070016import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070017import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070019import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070020import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070021import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070022import net.onrc.onos.ofcontroller.util.FlowEntry;
23import net.onrc.onos.ofcontroller.util.FlowEntryAction;
24import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070025import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070026import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
27import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
28import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070029import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070030import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070031import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080032import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
33
34import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070035
36import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070040 * Class for FlowPath Maintenance.
41 * This class listens for FlowEvents to:
42 * - Maintain a local cache of the Network Topology.
43 * - Detect FlowPaths impacted by Topology change.
44 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070045 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070046class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070047 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070048 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070049
50 private FlowManager flowManager; // The Flow Manager to use
51 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070052 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080053 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070054
55 // The queue with Flow Path and Topology Element updates
56 private BlockingQueue<EventEntry<?>> networkEvents =
57 new LinkedBlockingQueue<EventEntry<?>>();
58
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070059 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070060 private List<EventEntry<TopologyElement>> topologyEvents =
61 new LinkedList<EventEntry<TopologyElement>>();
62 private List<EventEntry<FlowPath>> flowPathEvents =
63 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070064 private List<EventEntry<FlowEntry>> flowEntryEvents =
65 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070066
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080067 // All internally computed Flow Paths
68 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
69
70 // The Flow Entries received as notifications with unmatched Flow Paths
71 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
72 new HashMap<Long, FlowEntry>();
73
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080074 //
75 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080076 // - The Flow Paths that should be recomputed
77 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080078 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080079 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080080 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
81 new HashMap<Long, FlowPath>();
82 private Map<Long, FlowPath> modifiedFlowPaths =
83 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080084 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
85 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080086
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070087 /**
88 * Constructor for a given Flow Manager and Datagrid Service.
89 *
90 * @param flowManager the Flow Manager to use.
91 * @param datagridService the Datagrid Service to use.
92 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070093 FlowEventHandler(FlowManager flowManager,
94 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070095 this.flowManager = flowManager;
96 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070097 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070098 }
99
100 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800101 * Get the network topology.
102 *
103 * @return the network topology.
104 */
105 protected Topology getTopology() { return this.topology; }
106
107 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800108 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700109 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800110 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700111 //
112 // Obtain the initial Topology state
113 //
114 Collection<TopologyElement> topologyElements =
115 datagridService.getAllTopologyElements();
116 for (TopologyElement topologyElement : topologyElements) {
117 EventEntry<TopologyElement> eventEntry =
118 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
119 topologyEvents.add(eventEntry);
120 }
121 //
122 // Obtain the initial Flow Path state
123 //
124 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
125 for (FlowPath flowPath : flowPaths) {
126 EventEntry<FlowPath> eventEntry =
127 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
128 flowPathEvents.add(eventEntry);
129 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700130 //
131 // Obtain the initial FlowEntry state
132 //
133 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
134 for (FlowEntry flowEntry : flowEntries) {
135 EventEntry<FlowEntry> eventEntry =
136 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
137 flowEntryEvents.add(eventEntry);
138 }
139
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800140 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800141 synchronized (allFlowPaths) {
142 processEvents();
143 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800144 }
145
146 /**
147 * Run the thread.
148 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800149 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800150 public void run() {
151 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700152
153 //
154 // The main loop
155 //
156 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
157 try {
158 while (true) {
159 EventEntry<?> eventEntry = networkEvents.take();
160 collection.add(eventEntry);
161 networkEvents.drainTo(collection);
162
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700163 //
164 // Demultiplex all events:
165 // - EventEntry<TopologyElement>
166 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700167 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700168 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700169 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800170 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700171 if (event.eventData() instanceof TopologyElement) {
172 EventEntry<TopologyElement> topologyEventEntry =
173 (EventEntry<TopologyElement>)event;
174 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800175 continue;
176 }
177
178 // FlowPath event
179 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700180 EventEntry<FlowPath> flowPathEventEntry =
181 (EventEntry<FlowPath>)event;
182 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800183 continue;
184 }
185
186 // FlowEntry event
187 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700188 EventEntry<FlowEntry> flowEntryEventEntry =
189 (EventEntry<FlowEntry>)event;
190 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800191 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700192 }
193 }
194 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700195
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700196 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800197 synchronized (allFlowPaths) {
198 processEvents();
199 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700200 }
201 } catch (Exception exception) {
202 log.debug("Exception processing Network Events: ", exception);
203 }
204 }
205
206 /**
207 * Process the events (if any)
208 */
209 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800210 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700211
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700212 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
213 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700214 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700215 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700216
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800217 processFlowPathEvents();
218 processTopologyEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800219 processFlowEntryEvents();
220
221 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800222 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800223 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800224 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800225 }
226
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800227 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800228 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800229
230 // Assign missing Flow Entry IDs
231 assignFlowEntryId(modifiedFlowEntries);
232
233 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800234 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800235 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800236 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
237 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800238
239 //
240 // Remove Flow Entries that were deleted
241 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800242 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800243 flowPath.dataPath().removeDeletedFlowEntries();
244
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800245 //
246 // Check if Flow Paths have been installed into all switches,
247 // and generate the appropriate events.
248 //
249 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
250
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800251 // Cleanup
252 topologyEvents.clear();
253 flowPathEvents.clear();
254 flowEntryEvents.clear();
255 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800256 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800257 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800258 checkIfInstalledFlowPaths.clear();
259 }
260
261 /**
262 * Check if Flow Paths have been installed into all switches,
263 * and generate the appropriate events.
264 *
265 * @param flowPaths the flowPaths to process.
266 */
267 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
268 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
269
270 Kryo kryo = kryoFactory.newKryo();
271
272 for (FlowPath flowPath : flowPaths) {
273 boolean isInstalled = true;
274
275 //
276 // Check whether all Flow Entries have been installed
277 //
278 for (FlowEntry flowEntry : flowPath.flowEntries()) {
279 if (flowEntry.flowEntrySwitchState() !=
280 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
281 isInstalled = false;
282 break;
283 }
284 }
285
286 if (isInstalled) {
287 // Create a copy and add it to the list
288 FlowPath copyFlowPath = kryo.copy(flowPath);
289 installedFlowPaths.add(copyFlowPath);
290 }
291 }
292 kryoFactory.deleteKryo(kryo);
293
294 // Generate an event for the installed Flow Path.
295 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800296 }
297
298 /**
299 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800300 *
301 * @param modifiedFlowPaths the Flow Paths to process.
302 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800303 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800304 private Collection<FlowEntry> extractModifiedFlowEntries(
305 Collection<FlowPath> modifiedFlowPaths) {
306 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800307
308 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800309 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800310 for (FlowEntry flowEntry : flowPath.flowEntries()) {
311 if (flowEntry.flowEntrySwitchState() ==
312 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800313 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800314 }
315 }
316 }
317 return modifiedFlowEntries;
318 }
319
320 /**
321 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800322 *
323 * @param modifiedFlowEnries the collection of Flow Entries that need
324 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800325 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800326 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800327 if (modifiedFlowEntries.isEmpty())
328 return;
329
330 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
331
332 //
333 // Assign the Flow Entry ID only for Flow Entries for my switches
334 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800335 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800336 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
337 if (mySwitch == null)
338 continue;
339 if (! flowEntry.isValidFlowEntryId()) {
340 long id = flowManager.getNextFlowEntryId();
341 flowEntry.setFlowEntryId(new FlowEntryId(id));
342 }
343 }
344 }
345
346 /**
347 * Process the Flow Path events.
348 */
349 private void processFlowPathEvents() {
350 //
351 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700352 //
353 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
354 FlowPath flowPath = eventEntry.eventData();
355
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800356 log.debug("Flow Event: {} {}", eventEntry.eventType(),
357 flowPath.toString());
358
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700359 switch (eventEntry.eventType()) {
360 case ENTRY_ADD: {
361 //
362 // Add a new Flow Path
363 //
364 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
365 //
366 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800367 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700368 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700369 }
370
371 switch (flowPath.flowPathType()) {
372 case FP_TYPE_SHORTEST_PATH:
373 //
374 // Reset the Data Path, in case it was set already, because
375 // we are going to recompute it anyway.
376 //
377 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800378 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
379 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700380 break;
381 case FP_TYPE_EXPLICIT_PATH:
382 //
383 // Mark all Flow Entries for installation in the switches.
384 //
385 for (FlowEntry flowEntry : flowPath.flowEntries()) {
386 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
387 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800388 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700389 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800390 case FP_TYPE_UNKNOWN:
391 log.error("FlowPath event with unknown type");
392 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700393 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800394 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700395
396 break;
397 }
398
399 case ENTRY_REMOVE: {
400 //
401 // Remove an existing Flow Path.
402 //
403 // Find the Flow Path, and mark the Flow and its Flow Entries
404 // for deletion.
405 //
406 FlowPath existingFlowPath =
407 allFlowPaths.get(flowPath.flowId().value());
408 if (existingFlowPath == null)
409 continue; // Nothing to do
410
411 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
412 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
413 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
414 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
415 }
416
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800417 // Remove the Flow Path from the internal state
418 Long key = existingFlowPath.flowId().value();
419 allFlowPaths.remove(key);
420 shouldRecomputeFlowPaths.remove(key);
421 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700422
423 break;
424 }
425 }
426 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800427 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700428
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800429 /**
430 * Process the Topology events.
431 */
432 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700433 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800434 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700435 //
436 boolean isTopologyModified = false;
437 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
438 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800439
440 log.debug("Topology Event: {} {}", eventEntry.eventType(),
441 topologyElement.toString());
442
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700443 switch (eventEntry.eventType()) {
444 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700445 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700446 break;
447 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700448 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700449 break;
450 }
451 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700452 if (isTopologyModified) {
453 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800454 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700455 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800456 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700457
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800458 /**
459 * Process the Flow Entry events.
460 */
461 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800462 FlowPath flowPath;
463 FlowEntry updatedFlowEntry;
464
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700465 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800466 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700467 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800468 if (! unmatchedFlowEntryAdd.isEmpty()) {
469 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
470 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
471 flowPath = allFlowPaths.get(flowEntry.flowId().value());
472 if (flowPath == null)
473 continue;
474 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
475 if (updatedFlowEntry == null) {
476 remainingUpdates.put(flowEntry.flowEntryId().value(),
477 flowEntry);
478 continue;
479 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800480 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700481 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800482 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700483 }
484
485 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800486 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700487 //
488 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
489 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800490
491 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
492 flowEntry.toString());
493
494 if ((! flowEntry.isValidFlowId()) ||
495 (! flowEntry.isValidFlowEntryId())) {
496 continue;
497 }
498
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700499 switch (eventEntry.eventType()) {
500 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800501 flowPath = allFlowPaths.get(flowEntry.flowId().value());
502 if (flowPath == null) {
503 // Flow Path not found: keep the entry for later matching
504 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
505 flowEntry);
506 break;
507 }
508 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
509 if (updatedFlowEntry == null) {
510 // Flow Entry not found: keep the entry for later matching
511 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
512 flowEntry);
513 break;
514 }
515 // Add the updated entry to the list of updated Flow Entries
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800516 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700517 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800518
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700519 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800520 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
521 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800522 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800523 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800524
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800525 flowPath = allFlowPaths.get(flowEntry.flowId().value());
526 if (flowPath == null) {
527 // Flow Path not found: ignore the update
528 break;
529 }
530 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
531 if (updatedFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800532 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800533 break;
534 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800535 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700536 break;
537 }
538 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700539 }
540
541 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800542 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700543 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800544 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700545 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800546 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700547 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800548 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
549 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700550 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800551 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700552 //
553 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800554 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
555 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700556 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800557 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700558
559 //
560 // Local Flow Entry match found
561 //
562 if (localFlowEntry.isValidFlowEntryId()) {
563 if (localFlowEntry.flowEntryId().value() !=
564 flowEntry.flowEntryId().value()) {
565 //
566 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800567 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700568 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800569 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700570 }
571 } else {
572 // Update the Flow Entry ID
573 FlowEntryId flowEntryId =
574 new FlowEntryId(flowEntry.flowEntryId().value());
575 localFlowEntry.setFlowEntryId(flowEntryId);
576 }
577
578 //
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800579 // Update the local Flow Entry, and keep state to check
580 // if the Flow Path has been installed.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700581 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800582 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700583 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800584 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800585 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700586 }
587
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800588 return null; // Entry not found
589 }
590
591 /**
592 * Update a Flow Entry because of an external ENTRY_REMOVE event.
593 *
594 * @param flowPath the FlowPath for the Flow Entry to update.
595 * @param flowEntry the FlowEntry with the new state.
596 * @return the updated Flow Entry if found, otherwise null.
597 */
598 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
599 FlowEntry flowEntry) {
600 //
601 // Iterate over all Flow Entries and find a match based on
602 // the Flow Entry ID.
603 //
604 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
605 if (! localFlowEntry.isValidFlowEntryId())
606 continue;
607 if (localFlowEntry.flowEntryId().value() !=
608 flowEntry.flowEntryId().value()) {
609 continue;
610 }
611 //
612 // Update the local Flow Entry.
613 //
614 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
615 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
616 return localFlowEntry;
617 }
618
619 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700620 }
621
622 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700623 * Recompute a Flow Path.
624 *
625 * @param flowPath the Flow Path to recompute.
626 * @return true if the recomputed Flow Path has changed, otherwise false.
627 */
628 private boolean recomputeFlowPath(FlowPath flowPath) {
629 boolean hasChanged = false;
630
631 //
632 // Test whether the Flow Path needs to be recomputed
633 //
634 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700635 case FP_TYPE_UNKNOWN:
636 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700637 case FP_TYPE_SHORTEST_PATH:
638 break;
639 case FP_TYPE_EXPLICIT_PATH:
640 return false; // An explicit path never changes
641 }
642
643 DataPath oldDataPath = flowPath.dataPath();
644
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700645 // Compute the new path
646 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
647 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700648 if (newDataPath == null) {
649 // We need the DataPath to compare the paths
650 newDataPath = new DataPath();
651 }
652 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
653
654 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700655 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700656 //
657 if (oldDataPath.flowEntries().size() !=
658 newDataPath.flowEntries().size()) {
659 hasChanged = true;
660 } else {
661 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
662 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
663 while (oldIter.hasNext() && newIter.hasNext()) {
664 FlowEntry oldFlowEntry = oldIter.next();
665 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700666 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
667 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700668 hasChanged = true;
669 break;
670 }
671 }
672 }
673 if (! hasChanged)
674 return hasChanged;
675
676 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700677 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700678 // - If a Flow Entry for a switch is in the old data path, but not
679 // in the new data path, then mark it for deletion.
680 // - If a Flow Entry for a switch is in the new data path, but not
681 // in the old data path, then mark it for addition.
682 // - If a Flow Entry for a switch is in both the old and the new
683 // data path, but it has changed, e.g., the incoming and/or outgoing
684 // port(s), then mark the old Flow Entry for deletion, and mark
685 // the new Flow Entry for addition.
686 // - If a Flow Entry for a switch is in both the old and the new
687 // data path, and it hasn't changed, then just keep it.
688 //
689 // NOTE: We use the Switch DPID of each entry to match the entries
690 //
691 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
692 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
693 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
694 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
695
696 // Prepare maps with the Flow Entries, so they are fast to lookup
697 for (FlowEntry flowEntry : oldDataPath.flowEntries())
698 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
699 for (FlowEntry flowEntry : newDataPath.flowEntries())
700 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
701
702 //
703 // Find the old Flow Entries that should be deleted
704 //
705 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
706 FlowEntry newFlowEntry =
707 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
708 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800709 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700710 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
711 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
712 deletedFlowEntries.add(oldFlowEntry);
713 }
714 }
715
716 //
717 // Find the new Flow Entries that should be added or updated
718 //
719 int idx = 0;
720 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
721 FlowEntry oldFlowEntry =
722 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
723
724 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700725 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
726 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700727 //
728 // Both Flow Entries are same
729 //
730 finalFlowEntries.add(oldFlowEntry);
731 idx++;
732 continue;
733 }
734
735 if (oldFlowEntry != null) {
736 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800737 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700738 //
739 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
740 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
741 deletedFlowEntries.add(oldFlowEntry);
742 }
743
744 //
745 // Add the new Flow Entry
746 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700747 //
748 // NOTE: Assign only the Flow ID.
749 // The Flow Entry ID is assigned later only for the Flow Entries
750 // this instance is responsible for.
751 //
752 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700753
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800754 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800755 // Copy the Flow timeouts
756 //
757 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
758 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
759
760 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800761 // Allocate the FlowEntryMatch by copying the default one
762 // from the FlowPath (if set).
763 //
764 FlowEntryMatch flowEntryMatch = null;
765 if (flowPath.flowEntryMatch() != null)
766 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
767 else
768 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700769 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800770
771 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700772 flowEntryMatch.enableInPort(newFlowEntry.inPort());
773
774 //
775 // Set the actions:
776 // If the first Flow Entry, copy the Flow Path actions to it.
777 //
778 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
779 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
780 FlowEntryActions flowActions =
781 new FlowEntryActions(flowPath.flowEntryActions());
782 for (FlowEntryAction action : flowActions.actions())
783 flowEntryActions.addAction(action);
784 }
785 idx++;
786
787 //
788 // Add the outgoing port output action
789 //
790 FlowEntryAction flowEntryAction = new FlowEntryAction();
791 flowEntryAction.setActionOutput(newFlowEntry.outPort());
792 flowEntryActions.addAction(flowEntryAction);
793
794 //
795 // Set the state of the new Flow Entry
796 //
797 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
798 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
799 finalFlowEntries.add(newFlowEntry);
800 }
801
802 //
803 // Replace the old Flow Entries with the new Flow Entries.
804 // Note that the Flow Entries that will be deleted are added at
805 // the end.
806 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800807 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700808 flowPath.dataPath().setFlowEntries(finalFlowEntries);
809
810 return hasChanged;
811 }
812
813 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700814 * Receive a notification that a Flow is added.
815 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700816 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700817 */
818 @Override
819 public void notificationRecvFlowAdded(FlowPath flowPath) {
820 EventEntry<FlowPath> eventEntry =
821 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
822 networkEvents.add(eventEntry);
823 }
824
825 /**
826 * Receive a notification that a Flow is removed.
827 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700828 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700829 */
830 @Override
831 public void notificationRecvFlowRemoved(FlowPath flowPath) {
832 EventEntry<FlowPath> eventEntry =
833 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
834 networkEvents.add(eventEntry);
835 }
836
837 /**
838 * Receive a notification that a Flow is updated.
839 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700840 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700841 */
842 @Override
843 public void notificationRecvFlowUpdated(FlowPath flowPath) {
844 // NOTE: The ADD and UPDATE events are processed in same way
845 EventEntry<FlowPath> eventEntry =
846 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
847 networkEvents.add(eventEntry);
848 }
849
850 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700851 * Receive a notification that a FlowEntry is added.
852 *
853 * @param flowEntry the FlowEntry that is added.
854 */
855 @Override
856 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
857 EventEntry<FlowEntry> eventEntry =
858 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
859 networkEvents.add(eventEntry);
860 }
861
862 /**
863 * Receive a notification that a FlowEntry is removed.
864 *
865 * @param flowEntry the FlowEntry that is removed.
866 */
867 @Override
868 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
869 EventEntry<FlowEntry> eventEntry =
870 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
871 networkEvents.add(eventEntry);
872 }
873
874 /**
875 * Receive a notification that a FlowEntry is updated.
876 *
877 * @param flowEntry the FlowEntry that is updated.
878 */
879 @Override
880 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
881 // NOTE: The ADD and UPDATE events are processed in same way
882 EventEntry<FlowEntry> eventEntry =
883 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
884 networkEvents.add(eventEntry);
885 }
886
887 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700888 * Receive a notification that a Topology Element is added.
889 *
890 * @param topologyElement the Topology Element that is added.
891 */
892 @Override
893 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
894 EventEntry<TopologyElement> eventEntry =
895 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
896 networkEvents.add(eventEntry);
897 }
898
899 /**
900 * Receive a notification that a Topology Element is removed.
901 *
902 * @param topologyElement the Topology Element that is removed.
903 */
904 @Override
905 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
906 EventEntry<TopologyElement> eventEntry =
907 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
908 networkEvents.add(eventEntry);
909 }
910
911 /**
912 * Receive a notification that a Topology Element is updated.
913 *
914 * @param topologyElement the Topology Element that is updated.
915 */
916 @Override
917 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
918 // NOTE: The ADD and UPDATE events are processed in same way
919 EventEntry<TopologyElement> eventEntry =
920 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
921 networkEvents.add(eventEntry);
922 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800923
924 /**
925 * Get a sorted copy of all Flow Paths.
926 *
927 * @return a sorted copy of all Flow Paths.
928 */
929 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
930 SortedMap<Long, FlowPath> sortedFlowPaths =
931 new TreeMap<Long, FlowPath>();
932
933 //
934 // TODO: For now we use serialization/deserialization to create
935 // a copy of each Flow Path. In the future, we should use proper
936 // copy constructors.
937 //
938 Kryo kryo = kryoFactory.newKryo();
939 synchronized (allFlowPaths) {
940 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
941 FlowPath origFlowPath = entry.getValue();
942 FlowPath copyFlowPath = kryo.copy(origFlowPath);
943 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
944 }
945 }
946 kryoFactory.deleteKryo(kryo);
947
948 return sortedFlowPaths;
949 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700950}