blob: 87cc4ce3d42b050044f8f762c38b3fe207f12667 [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() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800151 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800152 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700153
154 //
155 // The main loop
156 //
157 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
158 try {
159 while (true) {
160 EventEntry<?> eventEntry = networkEvents.take();
161 collection.add(eventEntry);
162 networkEvents.drainTo(collection);
163
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700164 //
165 // Demultiplex all events:
166 // - EventEntry<TopologyElement>
167 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700168 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700169 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700170 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800171 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700172 if (event.eventData() instanceof TopologyElement) {
173 EventEntry<TopologyElement> topologyEventEntry =
174 (EventEntry<TopologyElement>)event;
175 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800176 continue;
177 }
178
179 // FlowPath event
180 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700181 EventEntry<FlowPath> flowPathEventEntry =
182 (EventEntry<FlowPath>)event;
183 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800184 continue;
185 }
186
187 // FlowEntry event
188 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700189 EventEntry<FlowEntry> flowEntryEventEntry =
190 (EventEntry<FlowEntry>)event;
191 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800192 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700193 }
194 }
195 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700196
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700197 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800198 synchronized (allFlowPaths) {
199 processEvents();
200 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700201 }
202 } catch (Exception exception) {
203 log.debug("Exception processing Network Events: ", exception);
204 }
205 }
206
207 /**
208 * Process the events (if any)
209 */
210 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800211 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700212
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700213 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
214 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700215 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700216 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700217
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800218 processFlowPathEvents();
219 processTopologyEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800220 processFlowEntryEvents();
221
222 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800223 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800224 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800225 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800226 }
227
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800228 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800229 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800230
231 // Assign missing Flow Entry IDs
232 assignFlowEntryId(modifiedFlowEntries);
233
234 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800235 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800236 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800237 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
238 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800239
240 //
241 // Remove Flow Entries that were deleted
242 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800243 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800244 flowPath.dataPath().removeDeletedFlowEntries();
245
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800246 //
247 // Check if Flow Paths have been installed into all switches,
248 // and generate the appropriate events.
249 //
250 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
251
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800252 // Cleanup
253 topologyEvents.clear();
254 flowPathEvents.clear();
255 flowEntryEvents.clear();
256 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800257 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800258 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800259 checkIfInstalledFlowPaths.clear();
260 }
261
262 /**
263 * Check if Flow Paths have been installed into all switches,
264 * and generate the appropriate events.
265 *
266 * @param flowPaths the flowPaths to process.
267 */
268 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
269 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
270
271 Kryo kryo = kryoFactory.newKryo();
272
273 for (FlowPath flowPath : flowPaths) {
274 boolean isInstalled = true;
275
276 //
277 // Check whether all Flow Entries have been installed
278 //
279 for (FlowEntry flowEntry : flowPath.flowEntries()) {
280 if (flowEntry.flowEntrySwitchState() !=
281 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
282 isInstalled = false;
283 break;
284 }
285 }
286
287 if (isInstalled) {
288 // Create a copy and add it to the list
289 FlowPath copyFlowPath = kryo.copy(flowPath);
290 installedFlowPaths.add(copyFlowPath);
291 }
292 }
293 kryoFactory.deleteKryo(kryo);
294
295 // Generate an event for the installed Flow Path.
296 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800297 }
298
299 /**
300 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800301 *
302 * @param modifiedFlowPaths the Flow Paths to process.
303 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800304 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800305 private Collection<FlowEntry> extractModifiedFlowEntries(
306 Collection<FlowPath> modifiedFlowPaths) {
307 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800308
309 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800310 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800311 for (FlowEntry flowEntry : flowPath.flowEntries()) {
312 if (flowEntry.flowEntrySwitchState() ==
313 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800314 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800315 }
316 }
317 }
318 return modifiedFlowEntries;
319 }
320
321 /**
322 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800323 *
324 * @param modifiedFlowEnries the collection of Flow Entries that need
325 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800326 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800327 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800328 if (modifiedFlowEntries.isEmpty())
329 return;
330
331 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
332
333 //
334 // Assign the Flow Entry ID only for Flow Entries for my switches
335 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800336 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800337 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
338 if (mySwitch == null)
339 continue;
340 if (! flowEntry.isValidFlowEntryId()) {
341 long id = flowManager.getNextFlowEntryId();
342 flowEntry.setFlowEntryId(new FlowEntryId(id));
343 }
344 }
345 }
346
347 /**
348 * Process the Flow Path events.
349 */
350 private void processFlowPathEvents() {
351 //
352 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700353 //
354 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
355 FlowPath flowPath = eventEntry.eventData();
356
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800357 log.debug("Flow Event: {} {}", eventEntry.eventType(),
358 flowPath.toString());
359
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700360 switch (eventEntry.eventType()) {
361 case ENTRY_ADD: {
362 //
363 // Add a new Flow Path
364 //
365 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
366 //
367 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800368 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700369 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700370 }
371
372 switch (flowPath.flowPathType()) {
373 case FP_TYPE_SHORTEST_PATH:
374 //
375 // Reset the Data Path, in case it was set already, because
376 // we are going to recompute it anyway.
377 //
378 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800379 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
380 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700381 break;
382 case FP_TYPE_EXPLICIT_PATH:
383 //
384 // Mark all Flow Entries for installation in the switches.
385 //
386 for (FlowEntry flowEntry : flowPath.flowEntries()) {
387 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
388 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800389 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700390 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800391 case FP_TYPE_UNKNOWN:
392 log.error("FlowPath event with unknown type");
393 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700394 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800395 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700396
397 break;
398 }
399
400 case ENTRY_REMOVE: {
401 //
402 // Remove an existing Flow Path.
403 //
404 // Find the Flow Path, and mark the Flow and its Flow Entries
405 // for deletion.
406 //
407 FlowPath existingFlowPath =
408 allFlowPaths.get(flowPath.flowId().value());
409 if (existingFlowPath == null)
410 continue; // Nothing to do
411
412 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
413 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
414 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
415 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
416 }
417
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800418 // Remove the Flow Path from the internal state
419 Long key = existingFlowPath.flowId().value();
420 allFlowPaths.remove(key);
421 shouldRecomputeFlowPaths.remove(key);
422 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700423
424 break;
425 }
426 }
427 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800428 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700429
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800430 /**
431 * Process the Topology events.
432 */
433 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700434 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700436 //
437 boolean isTopologyModified = false;
438 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
439 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800440
441 log.debug("Topology Event: {} {}", eventEntry.eventType(),
442 topologyElement.toString());
443
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700444 switch (eventEntry.eventType()) {
445 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700446 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700447 break;
448 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700449 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700450 break;
451 }
452 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700453 if (isTopologyModified) {
454 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800455 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700456 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800457 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700458
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800459 /**
460 * Process the Flow Entry events.
461 */
462 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800463 FlowPath flowPath;
464 FlowEntry updatedFlowEntry;
465
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700466 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800467 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700468 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800469 if (! unmatchedFlowEntryAdd.isEmpty()) {
470 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
471 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
472 flowPath = allFlowPaths.get(flowEntry.flowId().value());
473 if (flowPath == null)
474 continue;
475 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
476 if (updatedFlowEntry == null) {
477 remainingUpdates.put(flowEntry.flowEntryId().value(),
478 flowEntry);
479 continue;
480 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800481 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700482 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800483 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700484 }
485
486 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800487 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700488 //
489 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
490 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800491
492 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
493 flowEntry.toString());
494
495 if ((! flowEntry.isValidFlowId()) ||
496 (! flowEntry.isValidFlowEntryId())) {
497 continue;
498 }
499
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700500 switch (eventEntry.eventType()) {
501 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800502 flowPath = allFlowPaths.get(flowEntry.flowId().value());
503 if (flowPath == null) {
504 // Flow Path not found: keep the entry for later matching
505 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
506 flowEntry);
507 break;
508 }
509 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
510 if (updatedFlowEntry == null) {
511 // Flow Entry not found: keep the entry for later matching
512 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
513 flowEntry);
514 break;
515 }
516 // Add the updated entry to the list of updated Flow Entries
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800517 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700518 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800519
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700520 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800521 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
522 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800523 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800524 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800525
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800526 flowPath = allFlowPaths.get(flowEntry.flowId().value());
527 if (flowPath == null) {
528 // Flow Path not found: ignore the update
529 break;
530 }
531 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
532 if (updatedFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800533 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800534 break;
535 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800536 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700537 break;
538 }
539 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700540 }
541
542 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800543 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700544 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800545 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700546 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800547 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700548 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800549 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
550 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700551 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800552 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700553 //
554 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800555 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
556 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700557 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800558 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700559
560 //
561 // Local Flow Entry match found
562 //
563 if (localFlowEntry.isValidFlowEntryId()) {
564 if (localFlowEntry.flowEntryId().value() !=
565 flowEntry.flowEntryId().value()) {
566 //
567 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800568 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700569 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800570 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700571 }
572 } else {
573 // Update the Flow Entry ID
574 FlowEntryId flowEntryId =
575 new FlowEntryId(flowEntry.flowEntryId().value());
576 localFlowEntry.setFlowEntryId(flowEntryId);
577 }
578
579 //
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800580 // Update the local Flow Entry, and keep state to check
581 // if the Flow Path has been installed.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700582 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800583 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700584 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800585 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800586 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700587 }
588
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800589 return null; // Entry not found
590 }
591
592 /**
593 * Update a Flow Entry because of an external ENTRY_REMOVE event.
594 *
595 * @param flowPath the FlowPath for the Flow Entry to update.
596 * @param flowEntry the FlowEntry with the new state.
597 * @return the updated Flow Entry if found, otherwise null.
598 */
599 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
600 FlowEntry flowEntry) {
601 //
602 // Iterate over all Flow Entries and find a match based on
603 // the Flow Entry ID.
604 //
605 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
606 if (! localFlowEntry.isValidFlowEntryId())
607 continue;
608 if (localFlowEntry.flowEntryId().value() !=
609 flowEntry.flowEntryId().value()) {
610 continue;
611 }
612 //
613 // Update the local Flow Entry.
614 //
615 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
616 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
617 return localFlowEntry;
618 }
619
620 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700621 }
622
623 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700624 * Recompute a Flow Path.
625 *
626 * @param flowPath the Flow Path to recompute.
627 * @return true if the recomputed Flow Path has changed, otherwise false.
628 */
629 private boolean recomputeFlowPath(FlowPath flowPath) {
630 boolean hasChanged = false;
631
632 //
633 // Test whether the Flow Path needs to be recomputed
634 //
635 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700636 case FP_TYPE_UNKNOWN:
637 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700638 case FP_TYPE_SHORTEST_PATH:
639 break;
640 case FP_TYPE_EXPLICIT_PATH:
641 return false; // An explicit path never changes
642 }
643
644 DataPath oldDataPath = flowPath.dataPath();
645
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700646 // Compute the new path
647 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
648 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700649 if (newDataPath == null) {
650 // We need the DataPath to compare the paths
651 newDataPath = new DataPath();
652 }
653 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
654
655 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700656 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700657 //
658 if (oldDataPath.flowEntries().size() !=
659 newDataPath.flowEntries().size()) {
660 hasChanged = true;
661 } else {
662 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
663 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
664 while (oldIter.hasNext() && newIter.hasNext()) {
665 FlowEntry oldFlowEntry = oldIter.next();
666 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700667 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
668 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700669 hasChanged = true;
670 break;
671 }
672 }
673 }
674 if (! hasChanged)
675 return hasChanged;
676
677 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700678 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700679 // - If a Flow Entry for a switch is in the old data path, but not
680 // in the new data path, then mark it for deletion.
681 // - If a Flow Entry for a switch is in the new data path, but not
682 // in the old data path, then mark it for addition.
683 // - If a Flow Entry for a switch is in both the old and the new
684 // data path, but it has changed, e.g., the incoming and/or outgoing
685 // port(s), then mark the old Flow Entry for deletion, and mark
686 // the new Flow Entry for addition.
687 // - If a Flow Entry for a switch is in both the old and the new
688 // data path, and it hasn't changed, then just keep it.
689 //
690 // NOTE: We use the Switch DPID of each entry to match the entries
691 //
692 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
693 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
694 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
695 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
696
697 // Prepare maps with the Flow Entries, so they are fast to lookup
698 for (FlowEntry flowEntry : oldDataPath.flowEntries())
699 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
700 for (FlowEntry flowEntry : newDataPath.flowEntries())
701 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
702
703 //
704 // Find the old Flow Entries that should be deleted
705 //
706 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
707 FlowEntry newFlowEntry =
708 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
709 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800710 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700711 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
712 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
713 deletedFlowEntries.add(oldFlowEntry);
714 }
715 }
716
717 //
718 // Find the new Flow Entries that should be added or updated
719 //
720 int idx = 0;
721 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
722 FlowEntry oldFlowEntry =
723 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
724
725 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700726 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
727 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700728 //
729 // Both Flow Entries are same
730 //
731 finalFlowEntries.add(oldFlowEntry);
732 idx++;
733 continue;
734 }
735
736 if (oldFlowEntry != null) {
737 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800738 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700739 //
740 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
741 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
742 deletedFlowEntries.add(oldFlowEntry);
743 }
744
745 //
746 // Add the new Flow Entry
747 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700748 //
749 // NOTE: Assign only the Flow ID.
750 // The Flow Entry ID is assigned later only for the Flow Entries
751 // this instance is responsible for.
752 //
753 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700754
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800755 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800756 // Copy the Flow timeouts
757 //
758 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
759 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
760
761 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800762 // Allocate the FlowEntryMatch by copying the default one
763 // from the FlowPath (if set).
764 //
765 FlowEntryMatch flowEntryMatch = null;
766 if (flowPath.flowEntryMatch() != null)
767 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
768 else
769 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700770 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800771
772 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700773 flowEntryMatch.enableInPort(newFlowEntry.inPort());
774
775 //
776 // Set the actions:
777 // If the first Flow Entry, copy the Flow Path actions to it.
778 //
779 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
780 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
781 FlowEntryActions flowActions =
782 new FlowEntryActions(flowPath.flowEntryActions());
783 for (FlowEntryAction action : flowActions.actions())
784 flowEntryActions.addAction(action);
785 }
786 idx++;
787
788 //
789 // Add the outgoing port output action
790 //
791 FlowEntryAction flowEntryAction = new FlowEntryAction();
792 flowEntryAction.setActionOutput(newFlowEntry.outPort());
793 flowEntryActions.addAction(flowEntryAction);
794
795 //
796 // Set the state of the new Flow Entry
797 //
798 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
799 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
800 finalFlowEntries.add(newFlowEntry);
801 }
802
803 //
804 // Replace the old Flow Entries with the new Flow Entries.
805 // Note that the Flow Entries that will be deleted are added at
806 // the end.
807 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800808 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700809 flowPath.dataPath().setFlowEntries(finalFlowEntries);
810
811 return hasChanged;
812 }
813
814 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700815 * Receive a notification that a Flow is added.
816 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700817 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700818 */
819 @Override
820 public void notificationRecvFlowAdded(FlowPath flowPath) {
821 EventEntry<FlowPath> eventEntry =
822 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
823 networkEvents.add(eventEntry);
824 }
825
826 /**
827 * Receive a notification that a Flow is removed.
828 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700829 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700830 */
831 @Override
832 public void notificationRecvFlowRemoved(FlowPath flowPath) {
833 EventEntry<FlowPath> eventEntry =
834 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
835 networkEvents.add(eventEntry);
836 }
837
838 /**
839 * Receive a notification that a Flow is updated.
840 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700841 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700842 */
843 @Override
844 public void notificationRecvFlowUpdated(FlowPath flowPath) {
845 // NOTE: The ADD and UPDATE events are processed in same way
846 EventEntry<FlowPath> eventEntry =
847 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
848 networkEvents.add(eventEntry);
849 }
850
851 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700852 * Receive a notification that a FlowEntry is added.
853 *
854 * @param flowEntry the FlowEntry that is added.
855 */
856 @Override
857 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
858 EventEntry<FlowEntry> eventEntry =
859 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
860 networkEvents.add(eventEntry);
861 }
862
863 /**
864 * Receive a notification that a FlowEntry is removed.
865 *
866 * @param flowEntry the FlowEntry that is removed.
867 */
868 @Override
869 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
870 EventEntry<FlowEntry> eventEntry =
871 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
872 networkEvents.add(eventEntry);
873 }
874
875 /**
876 * Receive a notification that a FlowEntry is updated.
877 *
878 * @param flowEntry the FlowEntry that is updated.
879 */
880 @Override
881 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
882 // NOTE: The ADD and UPDATE events are processed in same way
883 EventEntry<FlowEntry> eventEntry =
884 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
885 networkEvents.add(eventEntry);
886 }
887
888 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700889 * Receive a notification that a Topology Element is added.
890 *
891 * @param topologyElement the Topology Element that is added.
892 */
893 @Override
894 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
895 EventEntry<TopologyElement> eventEntry =
896 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
897 networkEvents.add(eventEntry);
898 }
899
900 /**
901 * Receive a notification that a Topology Element is removed.
902 *
903 * @param topologyElement the Topology Element that is removed.
904 */
905 @Override
906 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
907 EventEntry<TopologyElement> eventEntry =
908 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
909 networkEvents.add(eventEntry);
910 }
911
912 /**
913 * Receive a notification that a Topology Element is updated.
914 *
915 * @param topologyElement the Topology Element that is updated.
916 */
917 @Override
918 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
919 // NOTE: The ADD and UPDATE events are processed in same way
920 EventEntry<TopologyElement> eventEntry =
921 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
922 networkEvents.add(eventEntry);
923 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800924
925 /**
926 * Get a sorted copy of all Flow Paths.
927 *
928 * @return a sorted copy of all Flow Paths.
929 */
930 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
931 SortedMap<Long, FlowPath> sortedFlowPaths =
932 new TreeMap<Long, FlowPath>();
933
934 //
935 // TODO: For now we use serialization/deserialization to create
936 // a copy of each Flow Path. In the future, we should use proper
937 // copy constructors.
938 //
939 Kryo kryo = kryoFactory.newKryo();
940 synchronized (allFlowPaths) {
941 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
942 FlowPath origFlowPath = entry.getValue();
943 FlowPath copyFlowPath = kryo.copy(origFlowPath);
944 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
945 }
946 }
947 kryoFactory.deleteKryo(kryo);
948
949 return sortedFlowPaths;
950 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700951}