blob: 8000f49fcafaa9a90193c5c602434b07771dc71b [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;
Naoki Shiota0abe38d2014-01-07 15:31:22 -080017import net.onrc.onos.graph.GraphDBOperation;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070018import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070019import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070020import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070021import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080022import net.onrc.onos.ofcontroller.util.Dpid;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070023import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070024import net.onrc.onos.ofcontroller.util.FlowEntry;
25import net.onrc.onos.ofcontroller.util.FlowEntryAction;
26import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070027import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070028import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
29import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
30import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070031import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070032import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070033import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080034import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080035import net.onrc.onos.ofcontroller.util.Port;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080036import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
37
38import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070039
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
43/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070044 * Class for FlowPath Maintenance.
45 * This class listens for FlowEvents to:
46 * - Maintain a local cache of the Network Topology.
47 * - Detect FlowPaths impacted by Topology change.
48 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070049 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070050class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080051
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080052 private boolean enableOnrc2014MeasurementsFlows = true;
53 private boolean enableOnrc2014MeasurementsTopology = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080054
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070055 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070056 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Naoki Shiota0abe38d2014-01-07 15:31:22 -080057
Naoki Shiota0abe38d2014-01-07 15:31:22 -080058 private GraphDBOperation dbHandler;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070059 private FlowManager flowManager; // The Flow Manager to use
60 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070061 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080062 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070063
64 // The queue with Flow Path and Topology Element updates
65 private BlockingQueue<EventEntry<?>> networkEvents =
66 new LinkedBlockingQueue<EventEntry<?>>();
67
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070068 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070069 private List<EventEntry<TopologyElement>> topologyEvents =
70 new LinkedList<EventEntry<TopologyElement>>();
71 private List<EventEntry<FlowPath>> flowPathEvents =
72 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070073 private List<EventEntry<FlowEntry>> flowEntryEvents =
74 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -080075 private List<EventEntry<FlowId>> flowIdEvents =
76 new LinkedList<EventEntry<FlowId>>();
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080077 private List<EventEntry<Pair<FlowEntryId, Dpid>>> flowEntryIdEvents =
78 new LinkedList<EventEntry<Pair<FlowEntryId, Dpid>>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070079
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080080 // All internally computed Flow Paths
81 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
82
83 // The Flow Entries received as notifications with unmatched Flow Paths
84 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
85 new HashMap<Long, FlowEntry>();
86
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080087 //
88 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080089 // - The Flow Paths that should be recomputed
90 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080091 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080092 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080093 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
94 new HashMap<Long, FlowPath>();
95 private Map<Long, FlowPath> modifiedFlowPaths =
96 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080097 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
98 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080099
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700100 /**
101 * Constructor for a given Flow Manager and Datagrid Service.
102 *
103 * @param flowManager the Flow Manager to use.
104 * @param datagridService the Datagrid Service to use.
105 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700106 FlowEventHandler(FlowManager flowManager,
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800107 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700108 this.flowManager = flowManager;
109 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700110 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700111 }
112
113 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800114 * Get the network topology.
115 *
116 * @return the network topology.
117 */
118 protected Topology getTopology() { return this.topology; }
119
120 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800121 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700122 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800123 private void startup() {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800124 this.dbHandler = new GraphDBOperation("");
125
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700126 //
127 // Obtain the initial Topology state
128 //
129 Collection<TopologyElement> topologyElements =
130 datagridService.getAllTopologyElements();
131 for (TopologyElement topologyElement : topologyElements) {
132 EventEntry<TopologyElement> eventEntry =
133 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
134 topologyEvents.add(eventEntry);
135 }
136 //
137 // Obtain the initial Flow Path state
138 //
139 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
140 for (FlowPath flowPath : flowPaths) {
141 EventEntry<FlowPath> eventEntry =
142 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
143 flowPathEvents.add(eventEntry);
144 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700145 //
146 // Obtain the initial FlowEntry state
147 //
148 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
149 for (FlowEntry flowEntry : flowEntries) {
150 EventEntry<FlowEntry> eventEntry =
151 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
152 flowEntryEvents.add(eventEntry);
153 }
154
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800155 //
156 // Obtain the initial FlowId state
157 //
158 Collection<FlowId> flowIds = datagridService.getAllFlowIds();
159 for (FlowId flowId : flowIds) {
160 EventEntry<FlowId> eventEntry =
161 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
162 flowIdEvents.add(eventEntry);
163 }
164
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800165 //
166 // Obtain the initial FlowEntryId state
167 //
168 Collection<Pair<FlowEntryId, Dpid>> flowEntryIds =
169 datagridService.getAllFlowEntryIds();
170 for (Pair<FlowEntryId, Dpid> pair : flowEntryIds) {
171 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
172 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
173 flowEntryIdEvents.add(eventEntry);
174 }
175
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800176 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800177 synchronized (allFlowPaths) {
178 processEvents();
179 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800180 }
181
182 /**
183 * Run the thread.
184 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800185 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800186 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800187 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800188 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700189
190 //
191 // The main loop
192 //
193 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
194 try {
195 while (true) {
196 EventEntry<?> eventEntry = networkEvents.take();
197 collection.add(eventEntry);
198 networkEvents.drainTo(collection);
199
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700200 //
201 // Demultiplex all events:
202 // - EventEntry<TopologyElement>
203 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700204 // - EventEntry<FlowEntry>
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800205 // - EventEntry<FlowId>
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800206 // - EventEntry<Pair<FlowEntryId, Dpid>>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700207 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700208 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800209 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700210 if (event.eventData() instanceof TopologyElement) {
211 EventEntry<TopologyElement> topologyEventEntry =
212 (EventEntry<TopologyElement>)event;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800213
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700214 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800215 continue;
216 }
217
218 // FlowPath event
219 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700220 EventEntry<FlowPath> flowPathEventEntry =
221 (EventEntry<FlowPath>)event;
222 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800223 continue;
224 }
225
226 // FlowEntry event
227 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700228 EventEntry<FlowEntry> flowEntryEventEntry =
229 (EventEntry<FlowEntry>)event;
230 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800231 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700232 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800233
234 // FlowId event
235 if (event.eventData() instanceof FlowId) {
236 EventEntry<FlowId> flowIdEventEntry =
237 (EventEntry<FlowId>)event;
238 flowIdEvents.add(flowIdEventEntry);
239 continue;
240 }
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800241 // FlowEntryId event
242 if (event.eventData() instanceof Pair) {
243 EventEntry<Pair<FlowEntryId, Dpid>> flowEntryIdEventEntry =
244 (EventEntry<Pair<FlowEntryId, Dpid>>)event;
245 flowEntryIdEvents.add(flowEntryIdEventEntry);
246 continue;
247 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700248 }
249 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700250
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700251 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800252 synchronized (allFlowPaths) {
253 processEvents();
254 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700255 }
256 } catch (Exception exception) {
257 log.debug("Exception processing Network Events: ", exception);
258 }
259 }
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800260
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700261 /**
262 * Process the events (if any)
263 */
264 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800265 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700266
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800267 if (enableOnrc2014MeasurementsFlows) {
268
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800269 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty() &&
270 flowEntryIdEvents.isEmpty()) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800271 return; // Nothing to do
272 }
273
274 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
275
276 // Fetch and prepare my flows
277 prepareMyFlows(mySwitches);
278
279 // Fetch the topology
280 processTopologyEvents();
281
282 // Recompute all affected Flow Paths and keep only the modified
283 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
284 if (recomputeFlowPath(flowPath))
285 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
286 }
287
288 // Assign the Flow Entry ID as needed
289 for (FlowPath flowPath : modifiedFlowPaths.values()) {
290 for (FlowEntry flowEntry : flowPath.flowEntries()) {
291 if (! flowEntry.isValidFlowEntryId()) {
292 long id = flowManager.getNextFlowEntryId();
293 flowEntry.setFlowEntryId(new FlowEntryId(id));
294 }
295 }
296 }
297
298 // Extract my modified Flow Entries
299 modifiedFlowEntries = processFlowIdEvents(mySwitches);
300
301 //
302 // Push the modified state to the Flow Manager
303 //
304 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
305 modifiedFlowEntries);
306
307 // Cleanup
308 topologyEvents.clear();
309 flowIdEvents.clear();
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800310 flowEntryIdEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800311 //
312 allFlowPaths.clear();
313 shouldRecomputeFlowPaths.clear();
314 modifiedFlowPaths.clear();
315
316 return;
317 }
318
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700319 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800320 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700321 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700322 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700323
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800324 processFlowPathEvents();
325 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800326 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800327 processFlowEntryEvents();
328
329 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800330 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800331 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800332 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800333 }
334
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800335 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800336 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800337
338 // Assign missing Flow Entry IDs
339 assignFlowEntryId(modifiedFlowEntries);
340
341 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800342 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800343 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800344 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
345 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800346
347 //
348 // Remove Flow Entries that were deleted
349 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800350 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800351 flowPath.dataPath().removeDeletedFlowEntries();
352
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800353 //
354 // Check if Flow Paths have been installed into all switches,
355 // and generate the appropriate events.
356 //
357 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
358
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800359 // Cleanup
360 topologyEvents.clear();
361 flowPathEvents.clear();
362 flowEntryEvents.clear();
363 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800364 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800365 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800366 checkIfInstalledFlowPaths.clear();
367 }
368
369 /**
370 * Check if Flow Paths have been installed into all switches,
371 * and generate the appropriate events.
372 *
373 * @param flowPaths the flowPaths to process.
374 */
375 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
376 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
377
378 Kryo kryo = kryoFactory.newKryo();
379
380 for (FlowPath flowPath : flowPaths) {
381 boolean isInstalled = true;
382
383 //
384 // Check whether all Flow Entries have been installed
385 //
386 for (FlowEntry flowEntry : flowPath.flowEntries()) {
387 if (flowEntry.flowEntrySwitchState() !=
388 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
389 isInstalled = false;
390 break;
391 }
392 }
393
394 if (isInstalled) {
395 // Create a copy and add it to the list
396 FlowPath copyFlowPath = kryo.copy(flowPath);
397 installedFlowPaths.add(copyFlowPath);
398 }
399 }
400 kryoFactory.deleteKryo(kryo);
401
402 // Generate an event for the installed Flow Path.
403 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800404 }
405
406 /**
407 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800408 *
409 * @param modifiedFlowPaths the Flow Paths to process.
410 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800411 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800412 private Collection<FlowEntry> extractModifiedFlowEntries(
413 Collection<FlowPath> modifiedFlowPaths) {
414 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800415
416 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800417 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800418 for (FlowEntry flowEntry : flowPath.flowEntries()) {
419 if (flowEntry.flowEntrySwitchState() ==
420 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800421 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800422 }
423 }
424 }
425 return modifiedFlowEntries;
426 }
427
428 /**
429 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800430 *
431 * @param modifiedFlowEnries the collection of Flow Entries that need
432 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800433 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800434 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 if (modifiedFlowEntries.isEmpty())
436 return;
437
438 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
439
440 //
441 // Assign the Flow Entry ID only for Flow Entries for my switches
442 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800443 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800444 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
445 if (mySwitch == null)
446 continue;
447 if (! flowEntry.isValidFlowEntryId()) {
448 long id = flowManager.getNextFlowEntryId();
449 flowEntry.setFlowEntryId(new FlowEntryId(id));
450 }
451 }
452 }
453
454 /**
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800455 * Prepare my flows.
456 *
457 * @param mySwitches the collection of my switches.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800458 */
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800459 private void prepareMyFlows(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800460 if (! topologyEvents.isEmpty()) {
461 // Fetch my flows from the database
462 ArrayList<FlowPath> myFlows = FlowDatabaseOperation.getAllMyFlows(dbHandler, mySwitches);
463 for (FlowPath flowPath : myFlows) {
464 allFlowPaths.put(flowPath.flowId().value(), flowPath);
465
466 //
467 // TODO: Bug workaround / fix :
468 // method FlowDatabaseOperation.extractFlowEntry() doesn't
469 // fetch the inPort and outPort, hence we assign them here.
470 //
471 // Assign the inPort and outPort for the Flow Entries
472 for (FlowEntry flowEntry : flowPath.flowEntries()) {
473 // Set the inPort
474 do {
475 if (flowEntry.inPort() != null)
476 break;
477 if (flowEntry.flowEntryMatch() == null)
478 break;
479 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
480 flowEntry.setInPort(inPort);
481 } while (false);
482
483 // Set the outPort
484 do {
485 if (flowEntry.outPort() != null)
486 break;
487 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
488 if (fa.actionOutput() != null) {
489 Port outPort = new Port(fa.actionOutput().port().value());
490 flowEntry.setOutPort(outPort);
491 break;
492 }
493 }
494 } while (false);
495 }
496 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800497 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800498
499 //
500 // Automatically add all Flow ID events (for the Flows this instance
501 // is responsible for) to the collection of Flows to recompute.
502 //
503 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
504 FlowId flowId = eventEntry.eventData();
505 FlowPath flowPath = allFlowPaths.get(flowId.value());
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800506 if (flowPath == null) {
507 if (! topologyEvents.isEmpty())
508 continue; // Optimization: Not my flow
509 Dpid dpid = FlowDatabaseOperation.getFlowSourceDpid(dbHandler,
510 flowId);
511 if ((dpid != null) && (mySwitches.get(dpid.value()) != null)) {
512 flowPath = FlowDatabaseOperation.getFlow(dbHandler,
513 flowId);
514 }
515 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800516 if (flowPath != null) {
517 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
518 flowPath);
519 }
520 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800521 }
522
523 /**
524 * Process the Flow ID events.
525 *
526 * @param mySwitches the collection of my switches.
527 * @return a collection of modified Flow Entries this instance needs
528 * to push to its own switches.
529 */
530 private Collection<FlowEntry> processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
531 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
532
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800533 //
534 // Process all Flow ID events and update the appropriate state
535 //
536 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
537 FlowId flowId = eventEntry.eventData();
538
539 log.debug("Flow ID Event: {} {}", eventEntry.eventType(), flowId);
540
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800541 //
542 // Lookup the Flow ID in the Flows that were read from the
543 // database in in a previous step. If not found, read from
544 // the database.
545 //
546 FlowPath flowPath = allFlowPaths.get(flowId.value());
547 if (flowPath == null)
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800548 flowPath = FlowDatabaseOperation.getFlow(dbHandler, flowId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800549 if (flowPath == null) {
550 log.debug("Flow ID {} : Flow not found!", flowId);
551 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800552 }
553
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800554 // Collect only my flow entries that are not updated.
555 for (FlowEntry flowEntry : flowPath.flowEntries()) {
556 if (flowEntry.flowEntrySwitchState() !=
557 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
558 continue;
559 }
560 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
561 if (mySwitch == null)
562 continue;
563 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800564 }
565 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800566
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800567 return modifiedFlowEntries;
568 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800569
570 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800571 * Process the Flow Path events.
572 */
573 private void processFlowPathEvents() {
574 //
575 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700576 //
577 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
578 FlowPath flowPath = eventEntry.eventData();
579
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800580 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800581
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700582 switch (eventEntry.eventType()) {
583 case ENTRY_ADD: {
584 //
585 // Add a new Flow Path
586 //
587 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
588 //
589 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800590 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700591 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700592 }
593
594 switch (flowPath.flowPathType()) {
595 case FP_TYPE_SHORTEST_PATH:
596 //
597 // Reset the Data Path, in case it was set already, because
598 // we are going to recompute it anyway.
599 //
600 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800601 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
602 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700603 break;
604 case FP_TYPE_EXPLICIT_PATH:
605 //
606 // Mark all Flow Entries for installation in the switches.
607 //
608 for (FlowEntry flowEntry : flowPath.flowEntries()) {
609 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
610 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800611 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700612 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800613 case FP_TYPE_UNKNOWN:
614 log.error("FlowPath event with unknown type");
615 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700616 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800617 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700618
619 break;
620 }
621
622 case ENTRY_REMOVE: {
623 //
624 // Remove an existing Flow Path.
625 //
626 // Find the Flow Path, and mark the Flow and its Flow Entries
627 // for deletion.
628 //
629 FlowPath existingFlowPath =
630 allFlowPaths.get(flowPath.flowId().value());
631 if (existingFlowPath == null)
632 continue; // Nothing to do
633
634 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
635 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
636 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
637 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
638 }
639
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800640 // Remove the Flow Path from the internal state
641 Long key = existingFlowPath.flowId().value();
642 allFlowPaths.remove(key);
643 shouldRecomputeFlowPaths.remove(key);
644 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700645
646 break;
647 }
648 }
649 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800650 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700651
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800652 /**
653 * Process the Topology events.
654 */
655 private void processTopologyEvents() {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800656 if (enableOnrc2014MeasurementsTopology) {
657 if (topologyEvents.isEmpty())
658 return;
659 log.debug("[BEFORE] {}", topology.toString());
660 topology.readFromDatabase(dbHandler);
661 log.debug("[AFTER] {}", topology.toString());
662 shouldRecomputeFlowPaths.putAll(allFlowPaths);
663 return;
664 }
665
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700666 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800667 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700668 //
669 boolean isTopologyModified = false;
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800670 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
671 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800672
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800673 log.debug("Topology Event: {} {}", eventEntry.eventType(),
674 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800675
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800676 switch (eventEntry.eventType()) {
677 case ENTRY_ADD:
678 isTopologyModified |= topology.addTopologyElement(topologyElement);
679 break;
680 case ENTRY_REMOVE:
681 isTopologyModified |= topology.removeTopologyElement(topologyElement);
682 break;
683 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700684 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700685 if (isTopologyModified) {
686 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800687 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700688 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800689 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700690
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800691 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800692 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800693 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800694 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800695 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800696 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800697
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700698 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800699 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700700 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800701 if (! unmatchedFlowEntryAdd.isEmpty()) {
702 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
703 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800704 // log.debug("Processing Unmatched Flow Entry: {}",
705 // flowEntry.toString());
706
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800707 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800708 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800709 remainingUpdates.put(flowEntry.flowEntryId().value(),
710 flowEntry);
711 continue;
712 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800713 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
714 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800715 remainingUpdates.put(flowEntry.flowEntryId().value(),
716 flowEntry);
717 continue;
718 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800719 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
720 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
721 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700722 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800723 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700724 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800725 }
726
727 /**
728 * Process the Flow Entry events.
729 */
730 private void processFlowEntryEvents() {
731 FlowPath flowPath;
732 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700733
734 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800735 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700736 //
737 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
738 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800739
740 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800741 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800742
743 if ((! flowEntry.isValidFlowId()) ||
744 (! flowEntry.isValidFlowEntryId())) {
745 continue;
746 }
747
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700748 switch (eventEntry.eventType()) {
749 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800750 flowPath = allFlowPaths.get(flowEntry.flowId().value());
751 if (flowPath == null) {
752 // Flow Path not found: keep the entry for later matching
753 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
754 flowEntry);
755 break;
756 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800757 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
758 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800759 // Flow Entry not found: keep the entry for later matching
760 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
761 flowEntry);
762 break;
763 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800764 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
765 // Add the updated Flow Path to the list of updated paths
766 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
767 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700768 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800769
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700770 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800771 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
772 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800773 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800774 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800775
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800776 flowPath = allFlowPaths.get(flowEntry.flowId().value());
777 if (flowPath == null) {
778 // Flow Path not found: ignore the update
779 break;
780 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800781 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
782 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800783 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800784 break;
785 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800786 if (updateFlowEntryRemove(flowPath, localFlowEntry,
787 flowEntry)) {
788 // Add the updated Flow Path to the list of updated paths
789 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
790 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700791 break;
792 }
793 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700794 }
795
796 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800797 * Find a Flow Entry that should be updated because of an external
798 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700799 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800800 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800801 * @param newFlowEntry the FlowEntry with the new state.
802 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700803 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800804 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
805 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700806 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800807 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700808 //
809 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800810 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800811 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700812 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800813 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700814
815 //
816 // Local Flow Entry match found
817 //
818 if (localFlowEntry.isValidFlowEntryId()) {
819 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800820 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700821 //
822 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800823 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700824 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800825 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700826 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700827 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800828 return localFlowEntry;
829 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700830
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800831 return null; // Entry not found
832 }
833
834 /**
835 * Update a Flow Entry because of an external ENTRY_ADD event.
836 *
837 * @param flowPath the FlowPath for the Flow Entry to update.
838 * @param localFlowEntry the local Flow Entry to update.
839 * @param newFlowEntry the FlowEntry with the new state.
840 * @return true if the local Flow Entry was updated, otherwise false.
841 */
842 private boolean updateFlowEntryAdd(FlowPath flowPath,
843 FlowEntry localFlowEntry,
844 FlowEntry newFlowEntry) {
845 boolean updated = false;
846
847 if (localFlowEntry.flowEntryUserState() ==
848 FlowEntryUserState.FE_USER_DELETE) {
849 // Don't add-back a Flow Entry that is already deleted
850 return false;
851 }
852
853 if (! localFlowEntry.isValidFlowEntryId()) {
854 // Update the Flow Entry ID
855 FlowEntryId flowEntryId =
856 new FlowEntryId(newFlowEntry.flowEntryId().value());
857 localFlowEntry.setFlowEntryId(flowEntryId);
858 updated = true;
859 }
860
861 //
862 // Update the local Flow Entry, and keep state to check
863 // if the Flow Path has been installed.
864 //
865 if (localFlowEntry.flowEntryUserState() !=
866 newFlowEntry.flowEntryUserState()) {
867 localFlowEntry.setFlowEntryUserState(
868 newFlowEntry.flowEntryUserState());
869 updated = true;
870 }
871 if (localFlowEntry.flowEntrySwitchState() !=
872 newFlowEntry.flowEntrySwitchState()) {
873 localFlowEntry.setFlowEntrySwitchState(
874 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800875 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800876 updated = true;
877 }
878
879 return updated;
880 }
881
882 /**
883 * Find a Flow Entry that should be updated because of an external
884 * ENTRY_REMOVE event.
885 *
886 * @param flowPath the FlowPath for the Flow Entry to update.
887 * @param newFlowEntry the FlowEntry with the new state.
888 * @return the Flow Entry that should be updated if found, otherwise null.
889 */
890 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
891 FlowEntry newFlowEntry) {
892 //
893 // Iterate over all Flow Entries and find a match based on
894 // the Flow Entry ID.
895 //
896 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
897 if (! localFlowEntry.isValidFlowEntryId())
898 continue;
899 if (localFlowEntry.flowEntryId().value() !=
900 newFlowEntry.flowEntryId().value()) {
901 continue;
902 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800903 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700904 }
905
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800906 return null; // Entry not found
907 }
908
909 /**
910 * Update a Flow Entry because of an external ENTRY_REMOVE event.
911 *
912 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800913 * @param localFlowEntry the local Flow Entry to update.
914 * @param newFlowEntry the FlowEntry with the new state.
915 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800916 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800917 private boolean updateFlowEntryRemove(FlowPath flowPath,
918 FlowEntry localFlowEntry,
919 FlowEntry newFlowEntry) {
920 boolean updated = false;
921
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800922 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800923 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800924 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800925 if (localFlowEntry.flowEntryUserState() !=
926 newFlowEntry.flowEntryUserState()) {
927 localFlowEntry.setFlowEntryUserState(
928 newFlowEntry.flowEntryUserState());
929 updated = true;
930 }
931 if (localFlowEntry.flowEntrySwitchState() !=
932 newFlowEntry.flowEntrySwitchState()) {
933 localFlowEntry.setFlowEntrySwitchState(
934 newFlowEntry.flowEntrySwitchState());
935 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800936 }
937
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800938 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700939 }
940
941 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700942 * Recompute a Flow Path.
943 *
944 * @param flowPath the Flow Path to recompute.
945 * @return true if the recomputed Flow Path has changed, otherwise false.
946 */
947 private boolean recomputeFlowPath(FlowPath flowPath) {
948 boolean hasChanged = false;
949
950 //
951 // Test whether the Flow Path needs to be recomputed
952 //
953 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700954 case FP_TYPE_UNKNOWN:
955 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700956 case FP_TYPE_SHORTEST_PATH:
957 break;
958 case FP_TYPE_EXPLICIT_PATH:
959 return false; // An explicit path never changes
960 }
961
962 DataPath oldDataPath = flowPath.dataPath();
963
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700964 // Compute the new path
965 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
966 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700967 if (newDataPath == null) {
968 // We need the DataPath to compare the paths
969 newDataPath = new DataPath();
970 }
971 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
972
973 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700974 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700975 //
976 if (oldDataPath.flowEntries().size() !=
977 newDataPath.flowEntries().size()) {
978 hasChanged = true;
979 } else {
980 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
981 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
982 while (oldIter.hasNext() && newIter.hasNext()) {
983 FlowEntry oldFlowEntry = oldIter.next();
984 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700985 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
986 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700987 hasChanged = true;
988 break;
989 }
990 }
991 }
992 if (! hasChanged)
993 return hasChanged;
994
995 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700996 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700997 // - If a Flow Entry for a switch is in the old data path, but not
998 // in the new data path, then mark it for deletion.
999 // - If a Flow Entry for a switch is in the new data path, but not
1000 // in the old data path, then mark it for addition.
1001 // - If a Flow Entry for a switch is in both the old and the new
1002 // data path, but it has changed, e.g., the incoming and/or outgoing
1003 // port(s), then mark the old Flow Entry for deletion, and mark
1004 // the new Flow Entry for addition.
1005 // - If a Flow Entry for a switch is in both the old and the new
1006 // data path, and it hasn't changed, then just keep it.
1007 //
1008 // NOTE: We use the Switch DPID of each entry to match the entries
1009 //
1010 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1011 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1012 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1013 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1014
1015 // Prepare maps with the Flow Entries, so they are fast to lookup
1016 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1017 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1018 for (FlowEntry flowEntry : newDataPath.flowEntries())
1019 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1020
1021 //
1022 // Find the old Flow Entries that should be deleted
1023 //
1024 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1025 FlowEntry newFlowEntry =
1026 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1027 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001028 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001029 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1030 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1031 deletedFlowEntries.add(oldFlowEntry);
1032 }
1033 }
1034
1035 //
1036 // Find the new Flow Entries that should be added or updated
1037 //
1038 int idx = 0;
1039 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1040 FlowEntry oldFlowEntry =
1041 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1042
1043 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001044 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1045 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001046 //
1047 // Both Flow Entries are same
1048 //
1049 finalFlowEntries.add(oldFlowEntry);
1050 idx++;
1051 continue;
1052 }
1053
1054 if (oldFlowEntry != null) {
1055 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001056 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001057 //
1058 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1059 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1060 deletedFlowEntries.add(oldFlowEntry);
1061 }
1062
1063 //
1064 // Add the new Flow Entry
1065 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001066 //
1067 // NOTE: Assign only the Flow ID.
1068 // The Flow Entry ID is assigned later only for the Flow Entries
1069 // this instance is responsible for.
1070 //
1071 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001072
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001073 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001074 // Copy the Flow timeouts
1075 //
1076 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1077 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1078
1079 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001080 // Allocate the FlowEntryMatch by copying the default one
1081 // from the FlowPath (if set).
1082 //
1083 FlowEntryMatch flowEntryMatch = null;
1084 if (flowPath.flowEntryMatch() != null)
1085 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1086 else
1087 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001088 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001089
1090 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001091 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1092
1093 //
1094 // Set the actions:
1095 // If the first Flow Entry, copy the Flow Path actions to it.
1096 //
1097 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1098 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1099 FlowEntryActions flowActions =
1100 new FlowEntryActions(flowPath.flowEntryActions());
1101 for (FlowEntryAction action : flowActions.actions())
1102 flowEntryActions.addAction(action);
1103 }
1104 idx++;
1105
1106 //
1107 // Add the outgoing port output action
1108 //
1109 FlowEntryAction flowEntryAction = new FlowEntryAction();
1110 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1111 flowEntryActions.addAction(flowEntryAction);
1112
1113 //
1114 // Set the state of the new Flow Entry
1115 //
1116 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1117 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1118 finalFlowEntries.add(newFlowEntry);
1119 }
1120
1121 //
1122 // Replace the old Flow Entries with the new Flow Entries.
1123 // Note that the Flow Entries that will be deleted are added at
1124 // the end.
1125 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001126 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001127 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1128
1129 return hasChanged;
1130 }
1131
1132 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001133 * Receive a notification that a Flow is added.
1134 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001135 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001136 */
1137 @Override
1138 public void notificationRecvFlowAdded(FlowPath flowPath) {
1139 EventEntry<FlowPath> eventEntry =
1140 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1141 networkEvents.add(eventEntry);
1142 }
1143
1144 /**
1145 * Receive a notification that a Flow is removed.
1146 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001147 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001148 */
1149 @Override
1150 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1151 EventEntry<FlowPath> eventEntry =
1152 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1153 networkEvents.add(eventEntry);
1154 }
1155
1156 /**
1157 * Receive a notification that a Flow is updated.
1158 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001159 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001160 */
1161 @Override
1162 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1163 // NOTE: The ADD and UPDATE events are processed in same way
1164 EventEntry<FlowPath> eventEntry =
1165 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1166 networkEvents.add(eventEntry);
1167 }
1168
1169 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001170 * Receive a notification that a FlowEntry is added.
1171 *
1172 * @param flowEntry the FlowEntry that is added.
1173 */
1174 @Override
1175 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
1176 EventEntry<FlowEntry> eventEntry =
1177 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1178 networkEvents.add(eventEntry);
1179 }
1180
1181 /**
1182 * Receive a notification that a FlowEntry is removed.
1183 *
1184 * @param flowEntry the FlowEntry that is removed.
1185 */
1186 @Override
1187 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
1188 EventEntry<FlowEntry> eventEntry =
1189 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1190 networkEvents.add(eventEntry);
1191 }
1192
1193 /**
1194 * Receive a notification that a FlowEntry is updated.
1195 *
1196 * @param flowEntry the FlowEntry that is updated.
1197 */
1198 @Override
1199 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1200 // NOTE: The ADD and UPDATE events are processed in same way
1201 EventEntry<FlowEntry> eventEntry =
1202 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1203 networkEvents.add(eventEntry);
1204 }
1205
1206 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001207 * Receive a notification that a FlowId is added.
1208 *
1209 * @param flowId the FlowId that is added.
1210 */
1211 @Override
1212 public void notificationRecvFlowIdAdded(FlowId flowId) {
1213 EventEntry<FlowId> eventEntry =
1214 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1215 networkEvents.add(eventEntry);
1216 }
1217
1218 /**
1219 * Receive a notification that a FlowId is removed.
1220 *
1221 * @param flowId the FlowId that is removed.
1222 */
1223 @Override
1224 public void notificationRecvFlowIdRemoved(FlowId flowId) {
1225 EventEntry<FlowId> eventEntry =
1226 new EventEntry<FlowId>(EventEntry.Type.ENTRY_REMOVE, flowId);
1227 networkEvents.add(eventEntry);
1228 }
1229
1230 /**
1231 * Receive a notification that a FlowId is updated.
1232 *
1233 * @param flowId the FlowId that is updated.
1234 */
1235 @Override
1236 public void notificationRecvFlowIdUpdated(FlowId flowId) {
1237 // NOTE: The ADD and UPDATE events are processed in same way
1238 EventEntry<FlowId> eventEntry =
1239 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1240 networkEvents.add(eventEntry);
1241 }
1242
1243 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001244 * Receive a notification that a FlowEntryId is added.
1245 *
1246 * @param flowEntryId the FlowEntryId that is added.
1247 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1248 */
1249 @Override
1250 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1251 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001252 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1253
1254 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1255 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001256 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001257 }
1258
1259 /**
1260 * Receive a notification that a FlowEntryId is removed.
1261 *
1262 * @param flowEntryId the FlowEntryId that is removed.
1263 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1264 */
1265 @Override
1266 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1267 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001268 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1269
1270 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1271 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001272 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001273 }
1274
1275 /**
1276 * Receive a notification that a FlowEntryId is updated.
1277 *
1278 * @param flowEntryId the FlowEntryId that is updated.
1279 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1280 */
1281 @Override
1282 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1283 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001284 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1285
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001286 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001287 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1288 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001289 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001290 }
1291
1292 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001293 * Receive a notification that a Topology Element is added.
1294 *
1295 * @param topologyElement the Topology Element that is added.
1296 */
1297 @Override
1298 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1299 EventEntry<TopologyElement> eventEntry =
1300 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1301 networkEvents.add(eventEntry);
1302 }
1303
1304 /**
1305 * Receive a notification that a Topology Element is removed.
1306 *
1307 * @param topologyElement the Topology Element that is removed.
1308 */
1309 @Override
1310 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1311 EventEntry<TopologyElement> eventEntry =
1312 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1313 networkEvents.add(eventEntry);
1314 }
1315
1316 /**
1317 * Receive a notification that a Topology Element is updated.
1318 *
1319 * @param topologyElement the Topology Element that is updated.
1320 */
1321 @Override
1322 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1323 // NOTE: The ADD and UPDATE events are processed in same way
1324 EventEntry<TopologyElement> eventEntry =
1325 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1326 networkEvents.add(eventEntry);
1327 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001328
1329 /**
1330 * Get a sorted copy of all Flow Paths.
1331 *
1332 * @return a sorted copy of all Flow Paths.
1333 */
1334 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1335 SortedMap<Long, FlowPath> sortedFlowPaths =
1336 new TreeMap<Long, FlowPath>();
1337
1338 //
1339 // TODO: For now we use serialization/deserialization to create
1340 // a copy of each Flow Path. In the future, we should use proper
1341 // copy constructors.
1342 //
1343 Kryo kryo = kryoFactory.newKryo();
1344 synchronized (allFlowPaths) {
1345 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1346 FlowPath origFlowPath = entry.getValue();
1347 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1348 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1349 }
1350 }
1351 kryoFactory.deleteKryo(kryo);
1352
1353 return sortedFlowPaths;
1354 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001355}