blob: 3dc80c2e51b32fc87d9f2af94873fee622a7ccdc [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;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -080011import java.util.Timer;
12import java.util.TimerTask;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080013import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070014import java.util.concurrent.BlockingQueue;
15import java.util.concurrent.LinkedBlockingQueue;
16
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080017import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.datagrid.IDatagridService;
Naoki Shiota0abe38d2014-01-07 15:31:22 -080019import net.onrc.onos.graph.GraphDBOperation;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070020import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070021import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070022import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070023import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080024import net.onrc.onos.ofcontroller.util.Dpid;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070025import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070026import net.onrc.onos.ofcontroller.util.FlowEntry;
27import net.onrc.onos.ofcontroller.util.FlowEntryAction;
28import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070029import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070030import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
31import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
32import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070033import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070034import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070035import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080036import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080037import net.onrc.onos.ofcontroller.util.Port;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080038import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
39
40import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070041
42import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
45/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070046 * Class for FlowPath Maintenance.
47 * This class listens for FlowEvents to:
48 * - Maintain a local cache of the Network Topology.
49 * - Detect FlowPaths impacted by Topology change.
50 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070051 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070052class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080053
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080054 private boolean enableOnrc2014MeasurementsFlows = true;
55 private boolean enableOnrc2014MeasurementsTopology = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080056
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070057 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070058 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Naoki Shiota0abe38d2014-01-07 15:31:22 -080059
Naoki Shiota0abe38d2014-01-07 15:31:22 -080060 private GraphDBOperation dbHandler;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -080061
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070062 private FlowManager flowManager; // The Flow Manager to use
63 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070064 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080065 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070066
67 // The queue with Flow Path and Topology Element updates
68 private BlockingQueue<EventEntry<?>> networkEvents =
69 new LinkedBlockingQueue<EventEntry<?>>();
70
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070071 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070072 private List<EventEntry<TopologyElement>> topologyEvents =
73 new LinkedList<EventEntry<TopologyElement>>();
74 private List<EventEntry<FlowPath>> flowPathEvents =
75 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070076 private List<EventEntry<FlowEntry>> flowEntryEvents =
77 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -080078 private List<EventEntry<FlowId>> flowIdEvents =
79 new LinkedList<EventEntry<FlowId>>();
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080080 private List<EventEntry<Pair<FlowEntryId, Dpid>>> flowEntryIdEvents =
81 new LinkedList<EventEntry<Pair<FlowEntryId, Dpid>>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070082
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080083 // All internally computed Flow Paths
84 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
85
86 // The Flow Entries received as notifications with unmatched Flow Paths
87 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
88 new HashMap<Long, FlowEntry>();
89
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080090 //
91 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080092 // - The Flow Paths that should be recomputed
93 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080094 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080095 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080096 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
97 new HashMap<Long, FlowPath>();
98 private Map<Long, FlowPath> modifiedFlowPaths =
99 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800100 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
101 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800102
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700103 /**
104 * Constructor for a given Flow Manager and Datagrid Service.
105 *
106 * @param flowManager the Flow Manager to use.
107 * @param datagridService the Datagrid Service to use.
108 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700109 FlowEventHandler(FlowManager flowManager,
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800110 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700111 this.flowManager = flowManager;
112 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700113 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700114 }
115
116 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800117 * Get the network topology.
118 *
119 * @return the network topology.
120 */
121 protected Topology getTopology() { return this.topology; }
122
123 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800124 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700125 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800126 private void startup() {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800127 this.dbHandler = new GraphDBOperation("");
128
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700129 //
130 // Obtain the initial Topology state
131 //
132 Collection<TopologyElement> topologyElements =
133 datagridService.getAllTopologyElements();
134 for (TopologyElement topologyElement : topologyElements) {
135 EventEntry<TopologyElement> eventEntry =
136 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
137 topologyEvents.add(eventEntry);
138 }
139 //
140 // Obtain the initial Flow Path state
141 //
142 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
143 for (FlowPath flowPath : flowPaths) {
144 EventEntry<FlowPath> eventEntry =
145 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
146 flowPathEvents.add(eventEntry);
147 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700148 //
149 // Obtain the initial FlowEntry state
150 //
151 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
152 for (FlowEntry flowEntry : flowEntries) {
153 EventEntry<FlowEntry> eventEntry =
154 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
155 flowEntryEvents.add(eventEntry);
156 }
157
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800158 //
159 // Obtain the initial FlowId state
160 //
161 Collection<FlowId> flowIds = datagridService.getAllFlowIds();
162 for (FlowId flowId : flowIds) {
163 EventEntry<FlowId> eventEntry =
164 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
165 flowIdEvents.add(eventEntry);
166 }
167
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800168 //
169 // Obtain the initial FlowEntryId state
170 //
171 Collection<Pair<FlowEntryId, Dpid>> flowEntryIds =
172 datagridService.getAllFlowEntryIds();
173 for (Pair<FlowEntryId, Dpid> pair : flowEntryIds) {
174 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
175 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
176 flowEntryIdEvents.add(eventEntry);
177 }
178
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800179 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800180 synchronized (allFlowPaths) {
181 processEvents();
182 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800183 }
184
185 /**
186 * Run the thread.
187 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800188 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800189 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800190 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800191 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700192
193 //
194 // The main loop
195 //
196 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
197 try {
198 while (true) {
199 EventEntry<?> eventEntry = networkEvents.take();
200 collection.add(eventEntry);
201 networkEvents.drainTo(collection);
202
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700203 //
204 // Demultiplex all events:
205 // - EventEntry<TopologyElement>
206 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700207 // - EventEntry<FlowEntry>
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800208 // - EventEntry<FlowId>
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800209 // - EventEntry<Pair<FlowEntryId, Dpid>>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700210 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700211 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800212 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700213 if (event.eventData() instanceof TopologyElement) {
214 EventEntry<TopologyElement> topologyEventEntry =
215 (EventEntry<TopologyElement>)event;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800216
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700217 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800218 continue;
219 }
220
221 // FlowPath event
222 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700223 EventEntry<FlowPath> flowPathEventEntry =
224 (EventEntry<FlowPath>)event;
225 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800226 continue;
227 }
228
229 // FlowEntry event
230 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700231 EventEntry<FlowEntry> flowEntryEventEntry =
232 (EventEntry<FlowEntry>)event;
233 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800234 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700235 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800236
237 // FlowId event
238 if (event.eventData() instanceof FlowId) {
239 EventEntry<FlowId> flowIdEventEntry =
240 (EventEntry<FlowId>)event;
241 flowIdEvents.add(flowIdEventEntry);
242 continue;
243 }
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800244 // FlowEntryId event
245 if (event.eventData() instanceof Pair) {
246 EventEntry<Pair<FlowEntryId, Dpid>> flowEntryIdEventEntry =
247 (EventEntry<Pair<FlowEntryId, Dpid>>)event;
248 flowEntryIdEvents.add(flowEntryIdEventEntry);
249 continue;
250 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700251 }
252 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700253
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700254 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800255 synchronized (allFlowPaths) {
256 processEvents();
257 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700258 }
259 } catch (Exception exception) {
260 log.debug("Exception processing Network Events: ", exception);
261 }
262 }
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800263
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700264 /**
265 * Process the events (if any)
266 */
267 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800268 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700269
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800270 if (enableOnrc2014MeasurementsFlows) {
271
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800272 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty() &&
273 flowEntryIdEvents.isEmpty()) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800274 return; // Nothing to do
275 }
276
277 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
278
279 // Fetch and prepare my flows
280 prepareMyFlows(mySwitches);
281
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800282 // Process the Flow ID events
283 processFlowIdEvents(mySwitches);
284
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800285 // Fetch the topology
286 processTopologyEvents();
287
288 // Recompute all affected Flow Paths and keep only the modified
289 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
290 if (recomputeFlowPath(flowPath))
291 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
292 }
293
294 // Assign the Flow Entry ID as needed
295 for (FlowPath flowPath : modifiedFlowPaths.values()) {
296 for (FlowEntry flowEntry : flowPath.flowEntries()) {
297 if (! flowEntry.isValidFlowEntryId()) {
298 long id = flowManager.getNextFlowEntryId();
299 flowEntry.setFlowEntryId(new FlowEntryId(id));
300 }
301 }
302 }
303
304 // Extract my modified Flow Entries
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800305 modifiedFlowEntries = processFlowEntryIdEvents(mySwitches);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800306
307 //
308 // Push the modified state to the Flow Manager
309 //
310 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
311 modifiedFlowEntries);
312
313 // Cleanup
314 topologyEvents.clear();
315 flowIdEvents.clear();
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800316 flowEntryIdEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800317 //
318 allFlowPaths.clear();
319 shouldRecomputeFlowPaths.clear();
320 modifiedFlowPaths.clear();
321
322 return;
323 }
324
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700325 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800326 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700327 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700328 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700329
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800330 processFlowPathEvents();
331 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800332 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800333 processFlowEntryEvents();
334
335 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800336 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800337 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800338 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800339 }
340
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800341 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800342 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800343
344 // Assign missing Flow Entry IDs
345 assignFlowEntryId(modifiedFlowEntries);
346
347 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800348 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800349 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800350 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
351 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800352
353 //
354 // Remove Flow Entries that were deleted
355 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800356 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800357 flowPath.dataPath().removeDeletedFlowEntries();
358
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800359 //
360 // Check if Flow Paths have been installed into all switches,
361 // and generate the appropriate events.
362 //
363 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
364
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800365 // Cleanup
366 topologyEvents.clear();
367 flowPathEvents.clear();
368 flowEntryEvents.clear();
369 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800370 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800371 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800372 checkIfInstalledFlowPaths.clear();
373 }
374
375 /**
376 * Check if Flow Paths have been installed into all switches,
377 * and generate the appropriate events.
378 *
379 * @param flowPaths the flowPaths to process.
380 */
381 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
382 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
383
384 Kryo kryo = kryoFactory.newKryo();
385
386 for (FlowPath flowPath : flowPaths) {
387 boolean isInstalled = true;
388
389 //
390 // Check whether all Flow Entries have been installed
391 //
392 for (FlowEntry flowEntry : flowPath.flowEntries()) {
393 if (flowEntry.flowEntrySwitchState() !=
394 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
395 isInstalled = false;
396 break;
397 }
398 }
399
400 if (isInstalled) {
401 // Create a copy and add it to the list
402 FlowPath copyFlowPath = kryo.copy(flowPath);
403 installedFlowPaths.add(copyFlowPath);
404 }
405 }
406 kryoFactory.deleteKryo(kryo);
407
408 // Generate an event for the installed Flow Path.
409 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800410 }
411
412 /**
413 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800414 *
415 * @param modifiedFlowPaths the Flow Paths to process.
416 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800417 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800418 private Collection<FlowEntry> extractModifiedFlowEntries(
419 Collection<FlowPath> modifiedFlowPaths) {
420 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800421
422 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800423 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800424 for (FlowEntry flowEntry : flowPath.flowEntries()) {
425 if (flowEntry.flowEntrySwitchState() ==
426 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800427 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800428 }
429 }
430 }
431 return modifiedFlowEntries;
432 }
433
434 /**
435 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800436 *
437 * @param modifiedFlowEnries the collection of Flow Entries that need
438 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800439 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800440 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800441 if (modifiedFlowEntries.isEmpty())
442 return;
443
444 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
445
446 //
447 // Assign the Flow Entry ID only for Flow Entries for my switches
448 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800449 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800450 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
451 if (mySwitch == null)
452 continue;
453 if (! flowEntry.isValidFlowEntryId()) {
454 long id = flowManager.getNextFlowEntryId();
455 flowEntry.setFlowEntryId(new FlowEntryId(id));
456 }
457 }
458 }
459
460 /**
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800461 * Prepare my flows.
462 *
463 * @param mySwitches the collection of my switches.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800464 */
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800465 private void prepareMyFlows(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800466 if (! topologyEvents.isEmpty()) {
467 // Fetch my flows from the database
468 ArrayList<FlowPath> myFlows = FlowDatabaseOperation.getAllMyFlows(dbHandler, mySwitches);
469 for (FlowPath flowPath : myFlows) {
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800470 log.debug("Found my flow: {}", flowPath);
471
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800472 allFlowPaths.put(flowPath.flowId().value(), flowPath);
473
474 //
475 // TODO: Bug workaround / fix :
476 // method FlowDatabaseOperation.extractFlowEntry() doesn't
477 // fetch the inPort and outPort, hence we assign them here.
478 //
479 // Assign the inPort and outPort for the Flow Entries
480 for (FlowEntry flowEntry : flowPath.flowEntries()) {
481 // Set the inPort
482 do {
483 if (flowEntry.inPort() != null)
484 break;
485 if (flowEntry.flowEntryMatch() == null)
486 break;
487 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
488 flowEntry.setInPort(inPort);
489 } while (false);
490
491 // Set the outPort
492 do {
493 if (flowEntry.outPort() != null)
494 break;
495 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
496 if (fa.actionOutput() != null) {
497 Port outPort = new Port(fa.actionOutput().port().value());
498 flowEntry.setOutPort(outPort);
499 break;
500 }
501 }
502 } while (false);
503 }
504 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800505 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800506 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800507
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800508 /**
509 * Process the Flow ID events.
510 *
511 * @param mySwitches the collection of my switches.
512 */
513 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800514 //
515 // Automatically add all Flow ID events (for the Flows this instance
516 // is responsible for) to the collection of Flows to recompute.
517 //
518 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
519 FlowId flowId = eventEntry.eventData();
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800520
521 log.debug("Flow ID Event: {} {}", eventEntry.eventType(), flowId);
522
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800523 FlowPath flowPath = allFlowPaths.get(flowId.value());
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800524 if (flowPath == null) {
525 if (! topologyEvents.isEmpty())
526 continue; // Optimization: Not my flow
527 Dpid dpid = FlowDatabaseOperation.getFlowSourceDpid(dbHandler,
528 flowId);
529 if ((dpid != null) && (mySwitches.get(dpid.value()) != null)) {
530 flowPath = FlowDatabaseOperation.getFlow(dbHandler,
531 flowId);
532 }
533 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800534 if (flowPath != null) {
535 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
536 flowPath);
537 }
538 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800539 }
540
541 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800542 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800543 *
544 * @param mySwitches the collection of my switches.
545 * @return a collection of modified Flow Entries this instance needs
546 * to push to its own switches.
547 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800548 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800549 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
550
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800551 //
552 // Process all Flow ID events and update the appropriate state
553 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800554 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
555 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
556 FlowEntryId flowEntryId = pair.first;
557 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800558
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800559 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
560 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800561
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800562 if (mySwitches.get(dpid.value()) == null)
563 continue;
564
565 // Fetch the Flow Entry
566 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
567 flowEntryId);
568 if (flowEntry == null) {
569 log.debug("Flow Entry ID {} : Flow Entry not found!",
570 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800571 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800572 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800573 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800574 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800575
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800576 return modifiedFlowEntries;
577 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800578
579 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800580 * Process the Flow Path events.
581 */
582 private void processFlowPathEvents() {
583 //
584 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700585 //
586 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
587 FlowPath flowPath = eventEntry.eventData();
588
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800589 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800590
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700591 switch (eventEntry.eventType()) {
592 case ENTRY_ADD: {
593 //
594 // Add a new Flow Path
595 //
596 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
597 //
598 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800599 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700600 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700601 }
602
603 switch (flowPath.flowPathType()) {
604 case FP_TYPE_SHORTEST_PATH:
605 //
606 // Reset the Data Path, in case it was set already, because
607 // we are going to recompute it anyway.
608 //
609 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800610 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
611 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700612 break;
613 case FP_TYPE_EXPLICIT_PATH:
614 //
615 // Mark all Flow Entries for installation in the switches.
616 //
617 for (FlowEntry flowEntry : flowPath.flowEntries()) {
618 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
619 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800620 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700621 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800622 case FP_TYPE_UNKNOWN:
623 log.error("FlowPath event with unknown type");
624 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700625 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800626 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700627
628 break;
629 }
630
631 case ENTRY_REMOVE: {
632 //
633 // Remove an existing Flow Path.
634 //
635 // Find the Flow Path, and mark the Flow and its Flow Entries
636 // for deletion.
637 //
638 FlowPath existingFlowPath =
639 allFlowPaths.get(flowPath.flowId().value());
640 if (existingFlowPath == null)
641 continue; // Nothing to do
642
643 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
644 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
645 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
646 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
647 }
648
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800649 // Remove the Flow Path from the internal state
650 Long key = existingFlowPath.flowId().value();
651 allFlowPaths.remove(key);
652 shouldRecomputeFlowPaths.remove(key);
653 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700654
655 break;
656 }
657 }
658 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800659 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700660
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800661 /**
662 * Process the Topology events.
663 */
664 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800665 boolean isTopologyModified = false;
666
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800667 if (enableOnrc2014MeasurementsTopology) {
668 if (topologyEvents.isEmpty())
669 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800670
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800671 // TODO: Code for debugging purpose only
672 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
673 TopologyElement topologyElement = eventEntry.eventData();
674 log.debug("Topology Event: {} {}", eventEntry.eventType(),
675 topologyElement.toString());
676 }
677
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800678 log.debug("[BEFORE] {}", topology.toString());
679
Pavlin Radoslavov737aa522014-01-09 15:35:00 -0800680 //
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800681 // TODO: Fake the unconditional topology read by checking the cache
682 // with the old topology and ignoring topology events that don't
683 // make any impact to the topology.
Pavlin Radoslavov737aa522014-01-09 15:35:00 -0800684 // This is needed aa workaround: if a port is down, we get
685 // up to three additional "Port Down" or "Link Down" events.
686 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800687 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
688 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -0800689
Pavlin Radoslavov737aa522014-01-09 15:35:00 -0800690 switch (eventEntry.eventType()) {
691 case ENTRY_ADD:
692 isTopologyModified |= topology.addTopologyElement(topologyElement);
693 break;
694 case ENTRY_REMOVE:
695 isTopologyModified |= topology.removeTopologyElement(topologyElement);
696 break;
697 }
698 if (isTopologyModified)
699 break;
700 }
701 if (! isTopologyModified) {
702 log.debug("Ignoring topology events that don't modify the topology");
703 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800704 }
705
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800706 topology.readFromDatabase(dbHandler);
707 log.debug("[AFTER] {}", topology.toString());
708 shouldRecomputeFlowPaths.putAll(allFlowPaths);
709 return;
710 }
711
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700712 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800713 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700714 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800715 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
716 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800717
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800718 log.debug("Topology Event: {} {}", eventEntry.eventType(),
719 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800720
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800721 switch (eventEntry.eventType()) {
722 case ENTRY_ADD:
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800723 synchronized (topology) {
724 isTopologyModified |= topology.addTopologyElement(topologyElement);
725 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800726 break;
727 case ENTRY_REMOVE:
Naoki Shiotaf74d5f32014-01-09 21:29:38 -0800728 synchronized (topology) {
729 isTopologyModified |= topology.removeTopologyElement(topologyElement);
730 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800731 break;
732 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700733 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700734 if (isTopologyModified) {
735 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800736 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700737 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800738 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700739
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800740 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800741 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800742 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800743 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800744 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800745 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800746
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700747 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800748 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700749 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800750 if (! unmatchedFlowEntryAdd.isEmpty()) {
751 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
752 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800753 // log.debug("Processing Unmatched Flow Entry: {}",
754 // flowEntry.toString());
755
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800756 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800757 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800758 remainingUpdates.put(flowEntry.flowEntryId().value(),
759 flowEntry);
760 continue;
761 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800762 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
763 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800764 remainingUpdates.put(flowEntry.flowEntryId().value(),
765 flowEntry);
766 continue;
767 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800768 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
769 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
770 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700771 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800772 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700773 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800774 }
775
776 /**
777 * Process the Flow Entry events.
778 */
779 private void processFlowEntryEvents() {
780 FlowPath flowPath;
781 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700782
783 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800784 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700785 //
786 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
787 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800788
789 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800790 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800791
792 if ((! flowEntry.isValidFlowId()) ||
793 (! flowEntry.isValidFlowEntryId())) {
794 continue;
795 }
796
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700797 switch (eventEntry.eventType()) {
798 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800799 flowPath = allFlowPaths.get(flowEntry.flowId().value());
800 if (flowPath == null) {
801 // Flow Path not found: keep the entry for later matching
802 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
803 flowEntry);
804 break;
805 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800806 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
807 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800808 // Flow Entry not found: keep the entry for later matching
809 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
810 flowEntry);
811 break;
812 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800813 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
814 // Add the updated Flow Path to the list of updated paths
815 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
816 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700817 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800818
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700819 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800820 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
821 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800822 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800823 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800824
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800825 flowPath = allFlowPaths.get(flowEntry.flowId().value());
826 if (flowPath == null) {
827 // Flow Path not found: ignore the update
828 break;
829 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800830 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
831 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800832 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800833 break;
834 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800835 if (updateFlowEntryRemove(flowPath, localFlowEntry,
836 flowEntry)) {
837 // Add the updated Flow Path to the list of updated paths
838 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
839 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700840 break;
841 }
842 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700843 }
844
845 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800846 * Find a Flow Entry that should be updated because of an external
847 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700848 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800849 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800850 * @param newFlowEntry the FlowEntry with the new state.
851 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700852 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800853 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
854 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700855 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800856 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700857 //
858 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800859 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800860 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700861 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800862 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700863
864 //
865 // Local Flow Entry match found
866 //
867 if (localFlowEntry.isValidFlowEntryId()) {
868 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800869 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700870 //
871 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800872 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700873 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800874 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700875 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700876 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800877 return localFlowEntry;
878 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700879
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800880 return null; // Entry not found
881 }
882
883 /**
884 * Update a Flow Entry because of an external ENTRY_ADD event.
885 *
886 * @param flowPath the FlowPath for the Flow Entry to update.
887 * @param localFlowEntry the local Flow Entry to update.
888 * @param newFlowEntry the FlowEntry with the new state.
889 * @return true if the local Flow Entry was updated, otherwise false.
890 */
891 private boolean updateFlowEntryAdd(FlowPath flowPath,
892 FlowEntry localFlowEntry,
893 FlowEntry newFlowEntry) {
894 boolean updated = false;
895
896 if (localFlowEntry.flowEntryUserState() ==
897 FlowEntryUserState.FE_USER_DELETE) {
898 // Don't add-back a Flow Entry that is already deleted
899 return false;
900 }
901
902 if (! localFlowEntry.isValidFlowEntryId()) {
903 // Update the Flow Entry ID
904 FlowEntryId flowEntryId =
905 new FlowEntryId(newFlowEntry.flowEntryId().value());
906 localFlowEntry.setFlowEntryId(flowEntryId);
907 updated = true;
908 }
909
910 //
911 // Update the local Flow Entry, and keep state to check
912 // if the Flow Path has been installed.
913 //
914 if (localFlowEntry.flowEntryUserState() !=
915 newFlowEntry.flowEntryUserState()) {
916 localFlowEntry.setFlowEntryUserState(
917 newFlowEntry.flowEntryUserState());
918 updated = true;
919 }
920 if (localFlowEntry.flowEntrySwitchState() !=
921 newFlowEntry.flowEntrySwitchState()) {
922 localFlowEntry.setFlowEntrySwitchState(
923 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800924 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800925 updated = true;
926 }
927
928 return updated;
929 }
930
931 /**
932 * Find a Flow Entry that should be updated because of an external
933 * ENTRY_REMOVE event.
934 *
935 * @param flowPath the FlowPath for the Flow Entry to update.
936 * @param newFlowEntry the FlowEntry with the new state.
937 * @return the Flow Entry that should be updated if found, otherwise null.
938 */
939 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
940 FlowEntry newFlowEntry) {
941 //
942 // Iterate over all Flow Entries and find a match based on
943 // the Flow Entry ID.
944 //
945 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
946 if (! localFlowEntry.isValidFlowEntryId())
947 continue;
948 if (localFlowEntry.flowEntryId().value() !=
949 newFlowEntry.flowEntryId().value()) {
950 continue;
951 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800952 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700953 }
954
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800955 return null; // Entry not found
956 }
957
958 /**
959 * Update a Flow Entry because of an external ENTRY_REMOVE event.
960 *
961 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800962 * @param localFlowEntry the local Flow Entry to update.
963 * @param newFlowEntry the FlowEntry with the new state.
964 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800965 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800966 private boolean updateFlowEntryRemove(FlowPath flowPath,
967 FlowEntry localFlowEntry,
968 FlowEntry newFlowEntry) {
969 boolean updated = false;
970
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800971 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800972 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800973 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800974 if (localFlowEntry.flowEntryUserState() !=
975 newFlowEntry.flowEntryUserState()) {
976 localFlowEntry.setFlowEntryUserState(
977 newFlowEntry.flowEntryUserState());
978 updated = true;
979 }
980 if (localFlowEntry.flowEntrySwitchState() !=
981 newFlowEntry.flowEntrySwitchState()) {
982 localFlowEntry.setFlowEntrySwitchState(
983 newFlowEntry.flowEntrySwitchState());
984 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800985 }
986
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800987 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700988 }
989
990 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700991 * Recompute a Flow Path.
992 *
993 * @param flowPath the Flow Path to recompute.
994 * @return true if the recomputed Flow Path has changed, otherwise false.
995 */
996 private boolean recomputeFlowPath(FlowPath flowPath) {
997 boolean hasChanged = false;
998
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -0800999 if (enableOnrc2014MeasurementsFlows) {
1000 // Cleanup the deleted Flow Entries from the earlier iteration
1001 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001002
1003 //
1004 // TODO: Fake it that the Flow Entries have been already pushed
1005 // into the switches, so we don't push them again.
1006 //
1007 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1008 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1009 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001010 }
1011
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001012 //
1013 // Test whether the Flow Path needs to be recomputed
1014 //
1015 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001016 case FP_TYPE_UNKNOWN:
1017 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001018 case FP_TYPE_SHORTEST_PATH:
1019 break;
1020 case FP_TYPE_EXPLICIT_PATH:
1021 return false; // An explicit path never changes
1022 }
1023
1024 DataPath oldDataPath = flowPath.dataPath();
1025
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001026 // Compute the new path
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001027 DataPath newDataPath;
1028 synchronized (topology) {
1029 newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001030 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001031 }
1032
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001033 if (newDataPath == null) {
1034 // We need the DataPath to compare the paths
1035 newDataPath = new DataPath();
1036 }
1037 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1038
1039 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001040 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001041 //
1042 if (oldDataPath.flowEntries().size() !=
1043 newDataPath.flowEntries().size()) {
1044 hasChanged = true;
1045 } else {
1046 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1047 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1048 while (oldIter.hasNext() && newIter.hasNext()) {
1049 FlowEntry oldFlowEntry = oldIter.next();
1050 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001051 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1052 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001053 hasChanged = true;
1054 break;
1055 }
1056 }
1057 }
1058 if (! hasChanged)
1059 return hasChanged;
1060
1061 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001062 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001063 // - If a Flow Entry for a switch is in the old data path, but not
1064 // in the new data path, then mark it for deletion.
1065 // - If a Flow Entry for a switch is in the new data path, but not
1066 // in the old data path, then mark it for addition.
1067 // - If a Flow Entry for a switch is in both the old and the new
1068 // data path, but it has changed, e.g., the incoming and/or outgoing
1069 // port(s), then mark the old Flow Entry for deletion, and mark
1070 // the new Flow Entry for addition.
1071 // - If a Flow Entry for a switch is in both the old and the new
1072 // data path, and it hasn't changed, then just keep it.
1073 //
1074 // NOTE: We use the Switch DPID of each entry to match the entries
1075 //
1076 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1077 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1078 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1079 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1080
1081 // Prepare maps with the Flow Entries, so they are fast to lookup
1082 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1083 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1084 for (FlowEntry flowEntry : newDataPath.flowEntries())
1085 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1086
1087 //
1088 // Find the old Flow Entries that should be deleted
1089 //
1090 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1091 FlowEntry newFlowEntry =
1092 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1093 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001094 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001095 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1096 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1097 deletedFlowEntries.add(oldFlowEntry);
1098 }
1099 }
1100
1101 //
1102 // Find the new Flow Entries that should be added or updated
1103 //
1104 int idx = 0;
1105 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1106 FlowEntry oldFlowEntry =
1107 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1108
1109 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001110 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1111 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001112 //
1113 // Both Flow Entries are same
1114 //
1115 finalFlowEntries.add(oldFlowEntry);
1116 idx++;
1117 continue;
1118 }
1119
1120 if (oldFlowEntry != null) {
1121 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001122 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001123 //
1124 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1125 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1126 deletedFlowEntries.add(oldFlowEntry);
1127 }
1128
1129 //
1130 // Add the new Flow Entry
1131 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001132 //
1133 // NOTE: Assign only the Flow ID.
1134 // The Flow Entry ID is assigned later only for the Flow Entries
1135 // this instance is responsible for.
1136 //
1137 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001138
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001139 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001140 // Copy the Flow timeouts
1141 //
1142 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1143 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1144
1145 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001146 // Allocate the FlowEntryMatch by copying the default one
1147 // from the FlowPath (if set).
1148 //
1149 FlowEntryMatch flowEntryMatch = null;
1150 if (flowPath.flowEntryMatch() != null)
1151 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1152 else
1153 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001154 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001155
1156 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001157 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1158
1159 //
1160 // Set the actions:
1161 // If the first Flow Entry, copy the Flow Path actions to it.
1162 //
1163 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1164 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1165 FlowEntryActions flowActions =
1166 new FlowEntryActions(flowPath.flowEntryActions());
1167 for (FlowEntryAction action : flowActions.actions())
1168 flowEntryActions.addAction(action);
1169 }
1170 idx++;
1171
1172 //
1173 // Add the outgoing port output action
1174 //
1175 FlowEntryAction flowEntryAction = new FlowEntryAction();
1176 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1177 flowEntryActions.addAction(flowEntryAction);
1178
1179 //
1180 // Set the state of the new Flow Entry
1181 //
1182 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1183 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1184 finalFlowEntries.add(newFlowEntry);
1185 }
1186
1187 //
1188 // Replace the old Flow Entries with the new Flow Entries.
1189 // Note that the Flow Entries that will be deleted are added at
1190 // the end.
1191 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001192 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001193 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1194
1195 return hasChanged;
1196 }
1197
1198 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001199 * Receive a notification that a Flow is added.
1200 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001201 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001202 */
1203 @Override
1204 public void notificationRecvFlowAdded(FlowPath flowPath) {
1205 EventEntry<FlowPath> eventEntry =
1206 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1207 networkEvents.add(eventEntry);
1208 }
1209
1210 /**
1211 * Receive a notification that a Flow is removed.
1212 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001213 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001214 */
1215 @Override
1216 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1217 EventEntry<FlowPath> eventEntry =
1218 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1219 networkEvents.add(eventEntry);
1220 }
1221
1222 /**
1223 * Receive a notification that a Flow is updated.
1224 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001225 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001226 */
1227 @Override
1228 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1229 // NOTE: The ADD and UPDATE events are processed in same way
1230 EventEntry<FlowPath> eventEntry =
1231 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1232 networkEvents.add(eventEntry);
1233 }
1234
1235 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001236 * Receive a notification that a FlowEntry is added.
1237 *
1238 * @param flowEntry the FlowEntry that is added.
1239 */
1240 @Override
1241 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
1242 EventEntry<FlowEntry> eventEntry =
1243 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1244 networkEvents.add(eventEntry);
1245 }
1246
1247 /**
1248 * Receive a notification that a FlowEntry is removed.
1249 *
1250 * @param flowEntry the FlowEntry that is removed.
1251 */
1252 @Override
1253 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
1254 EventEntry<FlowEntry> eventEntry =
1255 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1256 networkEvents.add(eventEntry);
1257 }
1258
1259 /**
1260 * Receive a notification that a FlowEntry is updated.
1261 *
1262 * @param flowEntry the FlowEntry that is updated.
1263 */
1264 @Override
1265 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1266 // NOTE: The ADD and UPDATE events are processed in same way
1267 EventEntry<FlowEntry> eventEntry =
1268 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1269 networkEvents.add(eventEntry);
1270 }
1271
1272 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001273 * Receive a notification that a FlowId is added.
1274 *
1275 * @param flowId the FlowId that is added.
1276 */
1277 @Override
1278 public void notificationRecvFlowIdAdded(FlowId flowId) {
1279 EventEntry<FlowId> eventEntry =
1280 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1281 networkEvents.add(eventEntry);
1282 }
1283
1284 /**
1285 * Receive a notification that a FlowId is removed.
1286 *
1287 * @param flowId the FlowId that is removed.
1288 */
1289 @Override
1290 public void notificationRecvFlowIdRemoved(FlowId flowId) {
1291 EventEntry<FlowId> eventEntry =
1292 new EventEntry<FlowId>(EventEntry.Type.ENTRY_REMOVE, flowId);
1293 networkEvents.add(eventEntry);
1294 }
1295
1296 /**
1297 * Receive a notification that a FlowId is updated.
1298 *
1299 * @param flowId the FlowId that is updated.
1300 */
1301 @Override
1302 public void notificationRecvFlowIdUpdated(FlowId flowId) {
1303 // NOTE: The ADD and UPDATE events are processed in same way
1304 EventEntry<FlowId> eventEntry =
1305 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1306 networkEvents.add(eventEntry);
1307 }
1308
1309 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001310 * Receive a notification that a FlowEntryId is added.
1311 *
1312 * @param flowEntryId the FlowEntryId that is added.
1313 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1314 */
1315 @Override
1316 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1317 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001318 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1319
1320 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1321 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001322 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001323 }
1324
1325 /**
1326 * Receive a notification that a FlowEntryId is removed.
1327 *
1328 * @param flowEntryId the FlowEntryId that is removed.
1329 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1330 */
1331 @Override
1332 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1333 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001334 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1335
1336 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1337 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001338 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001339 }
1340
1341 /**
1342 * Receive a notification that a FlowEntryId is updated.
1343 *
1344 * @param flowEntryId the FlowEntryId that is updated.
1345 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1346 */
1347 @Override
1348 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1349 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001350 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1351
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001352 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001353 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1354 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001355 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001356 }
1357
1358 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001359 * Receive a notification that a Topology Element is added.
1360 *
1361 * @param topologyElement the Topology Element that is added.
1362 */
1363 @Override
1364 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1365 EventEntry<TopologyElement> eventEntry =
1366 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1367 networkEvents.add(eventEntry);
1368 }
1369
1370 /**
1371 * Receive a notification that a Topology Element is removed.
1372 *
1373 * @param topologyElement the Topology Element that is removed.
1374 */
1375 @Override
1376 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1377 EventEntry<TopologyElement> eventEntry =
1378 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1379 networkEvents.add(eventEntry);
1380 }
1381
1382 /**
1383 * Receive a notification that a Topology Element is updated.
1384 *
1385 * @param topologyElement the Topology Element that is updated.
1386 */
1387 @Override
1388 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1389 // NOTE: The ADD and UPDATE events are processed in same way
1390 EventEntry<TopologyElement> eventEntry =
1391 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1392 networkEvents.add(eventEntry);
1393 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001394
1395 /**
1396 * Get a sorted copy of all Flow Paths.
1397 *
1398 * @return a sorted copy of all Flow Paths.
1399 */
1400 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1401 SortedMap<Long, FlowPath> sortedFlowPaths =
1402 new TreeMap<Long, FlowPath>();
1403
1404 //
1405 // TODO: For now we use serialization/deserialization to create
1406 // a copy of each Flow Path. In the future, we should use proper
1407 // copy constructors.
1408 //
1409 Kryo kryo = kryoFactory.newKryo();
1410 synchronized (allFlowPaths) {
1411 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1412 FlowPath origFlowPath = entry.getValue();
1413 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1414 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1415 }
1416 }
1417 kryoFactory.deleteKryo(kryo);
1418
1419 return sortedFlowPaths;
1420 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001421}