blob: f49b10ae8587ae672cb2f23b8376905eefd5eac8 [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
78 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080079 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
80 new HashMap<Long, FlowPath>();
81 private Map<Long, FlowPath> modifiedFlowPaths =
82 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080083
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070084 /**
85 * Constructor for a given Flow Manager and Datagrid Service.
86 *
87 * @param flowManager the Flow Manager to use.
88 * @param datagridService the Datagrid Service to use.
89 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070090 FlowEventHandler(FlowManager flowManager,
91 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070092 this.flowManager = flowManager;
93 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070094 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070095 }
96
97 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -080098 * Get the network topology.
99 *
100 * @return the network topology.
101 */
102 protected Topology getTopology() { return this.topology; }
103
104 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800105 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700106 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800107 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700108 //
109 // Obtain the initial Topology state
110 //
111 Collection<TopologyElement> topologyElements =
112 datagridService.getAllTopologyElements();
113 for (TopologyElement topologyElement : topologyElements) {
114 EventEntry<TopologyElement> eventEntry =
115 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
116 topologyEvents.add(eventEntry);
117 }
118 //
119 // Obtain the initial Flow Path state
120 //
121 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
122 for (FlowPath flowPath : flowPaths) {
123 EventEntry<FlowPath> eventEntry =
124 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
125 flowPathEvents.add(eventEntry);
126 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700127 //
128 // Obtain the initial FlowEntry state
129 //
130 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
131 for (FlowEntry flowEntry : flowEntries) {
132 EventEntry<FlowEntry> eventEntry =
133 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
134 flowEntryEvents.add(eventEntry);
135 }
136
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800137 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800138 synchronized (allFlowPaths) {
139 processEvents();
140 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800141 }
142
143 /**
144 * Run the thread.
145 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800146 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800147 public void run() {
148 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700149
150 //
151 // The main loop
152 //
153 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
154 try {
155 while (true) {
156 EventEntry<?> eventEntry = networkEvents.take();
157 collection.add(eventEntry);
158 networkEvents.drainTo(collection);
159
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700160 //
161 // Demultiplex all events:
162 // - EventEntry<TopologyElement>
163 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700164 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700165 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700166 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800167 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700168 if (event.eventData() instanceof TopologyElement) {
169 EventEntry<TopologyElement> topologyEventEntry =
170 (EventEntry<TopologyElement>)event;
171 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800172 continue;
173 }
174
175 // FlowPath event
176 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700177 EventEntry<FlowPath> flowPathEventEntry =
178 (EventEntry<FlowPath>)event;
179 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800180 continue;
181 }
182
183 // FlowEntry event
184 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700185 EventEntry<FlowEntry> flowEntryEventEntry =
186 (EventEntry<FlowEntry>)event;
187 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800188 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700189 }
190 }
191 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700192
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700193 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800194 synchronized (allFlowPaths) {
195 processEvents();
196 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700197 }
198 } catch (Exception exception) {
199 log.debug("Exception processing Network Events: ", exception);
200 }
201 }
202
203 /**
204 * Process the events (if any)
205 */
206 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800207 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700208
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700209 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
210 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700211 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700212 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700213
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800214 processFlowPathEvents();
215 processTopologyEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800216 processFlowEntryEvents();
217
218 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800219 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800220 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800221 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800222 }
223
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800224 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800225 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800226
227 // Assign missing Flow Entry IDs
228 assignFlowEntryId(modifiedFlowEntries);
229
230 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800231 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800232 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800233 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
234 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800235
236 //
237 // Remove Flow Entries that were deleted
238 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800239 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800240 flowPath.dataPath().removeDeletedFlowEntries();
241
242 // Cleanup
243 topologyEvents.clear();
244 flowPathEvents.clear();
245 flowEntryEvents.clear();
246 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800247 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800248 modifiedFlowPaths.clear();
249 }
250
251 /**
252 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800253 *
254 * @param modifiedFlowPaths the Flow Paths to process.
255 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800256 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800257 private Collection<FlowEntry> extractModifiedFlowEntries(
258 Collection<FlowPath> modifiedFlowPaths) {
259 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800260
261 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800262 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800263 for (FlowEntry flowEntry : flowPath.flowEntries()) {
264 if (flowEntry.flowEntrySwitchState() ==
265 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800266 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800267 }
268 }
269 }
270 return modifiedFlowEntries;
271 }
272
273 /**
274 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800275 *
276 * @param modifiedFlowEnries the collection of Flow Entries that need
277 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800278 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800279 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800280 if (modifiedFlowEntries.isEmpty())
281 return;
282
283 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
284
285 //
286 // Assign the Flow Entry ID only for Flow Entries for my switches
287 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800288 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800289 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
290 if (mySwitch == null)
291 continue;
292 if (! flowEntry.isValidFlowEntryId()) {
293 long id = flowManager.getNextFlowEntryId();
294 flowEntry.setFlowEntryId(new FlowEntryId(id));
295 }
296 }
297 }
298
299 /**
300 * Process the Flow Path events.
301 */
302 private void processFlowPathEvents() {
303 //
304 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700305 //
306 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
307 FlowPath flowPath = eventEntry.eventData();
308
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800309 log.debug("Flow Event: {} {}", eventEntry.eventType(),
310 flowPath.toString());
311
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700312 switch (eventEntry.eventType()) {
313 case ENTRY_ADD: {
314 //
315 // Add a new Flow Path
316 //
317 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
318 //
319 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800320 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700321 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700322 }
323
324 switch (flowPath.flowPathType()) {
325 case FP_TYPE_SHORTEST_PATH:
326 //
327 // Reset the Data Path, in case it was set already, because
328 // we are going to recompute it anyway.
329 //
330 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800331 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
332 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700333 break;
334 case FP_TYPE_EXPLICIT_PATH:
335 //
336 // Mark all Flow Entries for installation in the switches.
337 //
338 for (FlowEntry flowEntry : flowPath.flowEntries()) {
339 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
340 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800341 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700342 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800343 case FP_TYPE_UNKNOWN:
344 log.error("FlowPath event with unknown type");
345 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700346 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800347 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700348
349 break;
350 }
351
352 case ENTRY_REMOVE: {
353 //
354 // Remove an existing Flow Path.
355 //
356 // Find the Flow Path, and mark the Flow and its Flow Entries
357 // for deletion.
358 //
359 FlowPath existingFlowPath =
360 allFlowPaths.get(flowPath.flowId().value());
361 if (existingFlowPath == null)
362 continue; // Nothing to do
363
364 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
365 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
366 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
367 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
368 }
369
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800370 // Remove the Flow Path from the internal state
371 Long key = existingFlowPath.flowId().value();
372 allFlowPaths.remove(key);
373 shouldRecomputeFlowPaths.remove(key);
374 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700375
376 break;
377 }
378 }
379 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800380 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700381
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800382 /**
383 * Process the Topology events.
384 */
385 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700386 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800387 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700388 //
389 boolean isTopologyModified = false;
390 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
391 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800392
393 log.debug("Topology Event: {} {}", eventEntry.eventType(),
394 topologyElement.toString());
395
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700396 switch (eventEntry.eventType()) {
397 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700398 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700399 break;
400 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700401 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700402 break;
403 }
404 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700405 if (isTopologyModified) {
406 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800407 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700408 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800409 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700410
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800411 /**
412 * Process the Flow Entry events.
413 */
414 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800415 FlowPath flowPath;
416 FlowEntry updatedFlowEntry;
417
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700418 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800419 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700420 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800421 if (! unmatchedFlowEntryAdd.isEmpty()) {
422 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
423 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
424 flowPath = allFlowPaths.get(flowEntry.flowId().value());
425 if (flowPath == null)
426 continue;
427 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
428 if (updatedFlowEntry == null) {
429 remainingUpdates.put(flowEntry.flowEntryId().value(),
430 flowEntry);
431 continue;
432 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800433 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700434 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800435 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700436 }
437
438 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800439 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700440 //
441 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
442 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800443
444 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
445 flowEntry.toString());
446
447 if ((! flowEntry.isValidFlowId()) ||
448 (! flowEntry.isValidFlowEntryId())) {
449 continue;
450 }
451
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700452 switch (eventEntry.eventType()) {
453 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800454 flowPath = allFlowPaths.get(flowEntry.flowId().value());
455 if (flowPath == null) {
456 // Flow Path not found: keep the entry for later matching
457 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
458 flowEntry);
459 break;
460 }
461 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
462 if (updatedFlowEntry == null) {
463 // Flow Entry not found: keep the entry for later matching
464 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
465 flowEntry);
466 break;
467 }
468 // Add the updated entry to the list of updated Flow Entries
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800469 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700470 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800471
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700472 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800473 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
474 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800475 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800476 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800477
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800478 flowPath = allFlowPaths.get(flowEntry.flowId().value());
479 if (flowPath == null) {
480 // Flow Path not found: ignore the update
481 break;
482 }
483 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
484 if (updatedFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800485 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800486 break;
487 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800488 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700489 break;
490 }
491 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700492 }
493
494 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800495 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700496 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800497 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700498 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800499 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700500 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800501 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
502 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700503 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800504 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700505 //
506 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
508 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700509 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800510 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700511
512 //
513 // Local Flow Entry match found
514 //
515 if (localFlowEntry.isValidFlowEntryId()) {
516 if (localFlowEntry.flowEntryId().value() !=
517 flowEntry.flowEntryId().value()) {
518 //
519 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800520 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700521 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800522 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700523 }
524 } else {
525 // Update the Flow Entry ID
526 FlowEntryId flowEntryId =
527 new FlowEntryId(flowEntry.flowEntryId().value());
528 localFlowEntry.setFlowEntryId(flowEntryId);
529 }
530
531 //
532 // Update the local Flow Entry.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700533 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800534 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700535 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800536 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700537 }
538
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800539 return null; // Entry not found
540 }
541
542 /**
543 * Update a Flow Entry because of an external ENTRY_REMOVE event.
544 *
545 * @param flowPath the FlowPath for the Flow Entry to update.
546 * @param flowEntry the FlowEntry with the new state.
547 * @return the updated Flow Entry if found, otherwise null.
548 */
549 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
550 FlowEntry flowEntry) {
551 //
552 // Iterate over all Flow Entries and find a match based on
553 // the Flow Entry ID.
554 //
555 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
556 if (! localFlowEntry.isValidFlowEntryId())
557 continue;
558 if (localFlowEntry.flowEntryId().value() !=
559 flowEntry.flowEntryId().value()) {
560 continue;
561 }
562 //
563 // Update the local Flow Entry.
564 //
565 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
566 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
567 return localFlowEntry;
568 }
569
570 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700571 }
572
573 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700574 * Recompute a Flow Path.
575 *
576 * @param flowPath the Flow Path to recompute.
577 * @return true if the recomputed Flow Path has changed, otherwise false.
578 */
579 private boolean recomputeFlowPath(FlowPath flowPath) {
580 boolean hasChanged = false;
581
582 //
583 // Test whether the Flow Path needs to be recomputed
584 //
585 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700586 case FP_TYPE_UNKNOWN:
587 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700588 case FP_TYPE_SHORTEST_PATH:
589 break;
590 case FP_TYPE_EXPLICIT_PATH:
591 return false; // An explicit path never changes
592 }
593
594 DataPath oldDataPath = flowPath.dataPath();
595
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700596 // Compute the new path
597 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
598 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700599 if (newDataPath == null) {
600 // We need the DataPath to compare the paths
601 newDataPath = new DataPath();
602 }
603 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
604
605 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700606 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700607 //
608 if (oldDataPath.flowEntries().size() !=
609 newDataPath.flowEntries().size()) {
610 hasChanged = true;
611 } else {
612 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
613 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
614 while (oldIter.hasNext() && newIter.hasNext()) {
615 FlowEntry oldFlowEntry = oldIter.next();
616 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700617 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
618 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700619 hasChanged = true;
620 break;
621 }
622 }
623 }
624 if (! hasChanged)
625 return hasChanged;
626
627 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700628 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700629 // - If a Flow Entry for a switch is in the old data path, but not
630 // in the new data path, then mark it for deletion.
631 // - If a Flow Entry for a switch is in the new data path, but not
632 // in the old data path, then mark it for addition.
633 // - If a Flow Entry for a switch is in both the old and the new
634 // data path, but it has changed, e.g., the incoming and/or outgoing
635 // port(s), then mark the old Flow Entry for deletion, and mark
636 // the new Flow Entry for addition.
637 // - If a Flow Entry for a switch is in both the old and the new
638 // data path, and it hasn't changed, then just keep it.
639 //
640 // NOTE: We use the Switch DPID of each entry to match the entries
641 //
642 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
643 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
644 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
645 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
646
647 // Prepare maps with the Flow Entries, so they are fast to lookup
648 for (FlowEntry flowEntry : oldDataPath.flowEntries())
649 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
650 for (FlowEntry flowEntry : newDataPath.flowEntries())
651 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
652
653 //
654 // Find the old Flow Entries that should be deleted
655 //
656 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
657 FlowEntry newFlowEntry =
658 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
659 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800660 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700661 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
662 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
663 deletedFlowEntries.add(oldFlowEntry);
664 }
665 }
666
667 //
668 // Find the new Flow Entries that should be added or updated
669 //
670 int idx = 0;
671 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
672 FlowEntry oldFlowEntry =
673 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
674
675 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700676 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
677 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700678 //
679 // Both Flow Entries are same
680 //
681 finalFlowEntries.add(oldFlowEntry);
682 idx++;
683 continue;
684 }
685
686 if (oldFlowEntry != null) {
687 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800688 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700689 //
690 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
691 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
692 deletedFlowEntries.add(oldFlowEntry);
693 }
694
695 //
696 // Add the new Flow Entry
697 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700698 //
699 // NOTE: Assign only the Flow ID.
700 // The Flow Entry ID is assigned later only for the Flow Entries
701 // this instance is responsible for.
702 //
703 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700704
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800705 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800706 // Copy the Flow timeouts
707 //
708 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
709 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
710
711 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800712 // Allocate the FlowEntryMatch by copying the default one
713 // from the FlowPath (if set).
714 //
715 FlowEntryMatch flowEntryMatch = null;
716 if (flowPath.flowEntryMatch() != null)
717 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
718 else
719 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700720 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800721
722 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700723 flowEntryMatch.enableInPort(newFlowEntry.inPort());
724
725 //
726 // Set the actions:
727 // If the first Flow Entry, copy the Flow Path actions to it.
728 //
729 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
730 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
731 FlowEntryActions flowActions =
732 new FlowEntryActions(flowPath.flowEntryActions());
733 for (FlowEntryAction action : flowActions.actions())
734 flowEntryActions.addAction(action);
735 }
736 idx++;
737
738 //
739 // Add the outgoing port output action
740 //
741 FlowEntryAction flowEntryAction = new FlowEntryAction();
742 flowEntryAction.setActionOutput(newFlowEntry.outPort());
743 flowEntryActions.addAction(flowEntryAction);
744
745 //
746 // Set the state of the new Flow Entry
747 //
748 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
749 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
750 finalFlowEntries.add(newFlowEntry);
751 }
752
753 //
754 // Replace the old Flow Entries with the new Flow Entries.
755 // Note that the Flow Entries that will be deleted are added at
756 // the end.
757 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800758 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700759 flowPath.dataPath().setFlowEntries(finalFlowEntries);
760
761 return hasChanged;
762 }
763
764 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700765 * Receive a notification that a Flow is added.
766 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700767 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700768 */
769 @Override
770 public void notificationRecvFlowAdded(FlowPath flowPath) {
771 EventEntry<FlowPath> eventEntry =
772 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
773 networkEvents.add(eventEntry);
774 }
775
776 /**
777 * Receive a notification that a Flow is removed.
778 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700779 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700780 */
781 @Override
782 public void notificationRecvFlowRemoved(FlowPath flowPath) {
783 EventEntry<FlowPath> eventEntry =
784 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
785 networkEvents.add(eventEntry);
786 }
787
788 /**
789 * Receive a notification that a Flow is updated.
790 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700791 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700792 */
793 @Override
794 public void notificationRecvFlowUpdated(FlowPath flowPath) {
795 // NOTE: The ADD and UPDATE events are processed in same way
796 EventEntry<FlowPath> eventEntry =
797 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
798 networkEvents.add(eventEntry);
799 }
800
801 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700802 * Receive a notification that a FlowEntry is added.
803 *
804 * @param flowEntry the FlowEntry that is added.
805 */
806 @Override
807 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
808 EventEntry<FlowEntry> eventEntry =
809 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
810 networkEvents.add(eventEntry);
811 }
812
813 /**
814 * Receive a notification that a FlowEntry is removed.
815 *
816 * @param flowEntry the FlowEntry that is removed.
817 */
818 @Override
819 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
820 EventEntry<FlowEntry> eventEntry =
821 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
822 networkEvents.add(eventEntry);
823 }
824
825 /**
826 * Receive a notification that a FlowEntry is updated.
827 *
828 * @param flowEntry the FlowEntry that is updated.
829 */
830 @Override
831 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
832 // NOTE: The ADD and UPDATE events are processed in same way
833 EventEntry<FlowEntry> eventEntry =
834 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
835 networkEvents.add(eventEntry);
836 }
837
838 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700839 * Receive a notification that a Topology Element is added.
840 *
841 * @param topologyElement the Topology Element that is added.
842 */
843 @Override
844 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
845 EventEntry<TopologyElement> eventEntry =
846 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
847 networkEvents.add(eventEntry);
848 }
849
850 /**
851 * Receive a notification that a Topology Element is removed.
852 *
853 * @param topologyElement the Topology Element that is removed.
854 */
855 @Override
856 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
857 EventEntry<TopologyElement> eventEntry =
858 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
859 networkEvents.add(eventEntry);
860 }
861
862 /**
863 * Receive a notification that a Topology Element is updated.
864 *
865 * @param topologyElement the Topology Element that is updated.
866 */
867 @Override
868 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
869 // NOTE: The ADD and UPDATE events are processed in same way
870 EventEntry<TopologyElement> eventEntry =
871 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
872 networkEvents.add(eventEntry);
873 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800874
875 /**
876 * Get a sorted copy of all Flow Paths.
877 *
878 * @return a sorted copy of all Flow Paths.
879 */
880 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
881 SortedMap<Long, FlowPath> sortedFlowPaths =
882 new TreeMap<Long, FlowPath>();
883
884 //
885 // TODO: For now we use serialization/deserialization to create
886 // a copy of each Flow Path. In the future, we should use proper
887 // copy constructors.
888 //
889 Kryo kryo = kryoFactory.newKryo();
890 synchronized (allFlowPaths) {
891 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
892 FlowPath origFlowPath = entry.getValue();
893 FlowPath copyFlowPath = kryo.copy(origFlowPath);
894 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
895 }
896 }
897 kryoFactory.deleteKryo(kryo);
898
899 return sortedFlowPaths;
900 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700901}