blob: c36c53a22d54ad51e2219f7ee4b47dec9415224c [file] [log] [blame]
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
2
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07003import java.util.ArrayList;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07004import java.util.Collection;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07005import java.util.HashMap;
6import java.util.Iterator;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07007import java.util.LinkedList;
8import java.util.List;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07009import java.util.Map;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
11import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.LinkedBlockingQueue;
14
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070016import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070017import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070019import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070020import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070021import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070022import net.onrc.onos.ofcontroller.util.FlowEntry;
23import net.onrc.onos.ofcontroller.util.FlowEntryAction;
24import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070025import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070026import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
27import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
28import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070029import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070030import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070031import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080032import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
33
34import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070035
36import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070040 * Class for FlowPath Maintenance.
41 * This class listens for FlowEvents to:
42 * - Maintain a local cache of the Network Topology.
43 * - Detect FlowPaths impacted by Topology change.
44 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070045 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070046class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070047 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070048 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070049
50 private FlowManager flowManager; // The Flow Manager to use
51 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070052 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080053 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070054
55 // The queue with Flow Path and Topology Element updates
56 private BlockingQueue<EventEntry<?>> networkEvents =
57 new LinkedBlockingQueue<EventEntry<?>>();
58
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070059 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070060 private List<EventEntry<TopologyElement>> topologyEvents =
61 new LinkedList<EventEntry<TopologyElement>>();
62 private List<EventEntry<FlowPath>> flowPathEvents =
63 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070064 private List<EventEntry<FlowEntry>> flowEntryEvents =
65 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070066
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080067 // All internally computed Flow Paths
68 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
69
70 // The Flow Entries received as notifications with unmatched Flow Paths
71 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
72 new HashMap<Long, FlowEntry>();
73
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080074 //
75 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080076 // - The Flow Paths that should be recomputed
77 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080078 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080079 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080080 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
81 new HashMap<Long, FlowPath>();
82 private Map<Long, FlowPath> modifiedFlowPaths =
83 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080084 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
85 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080086
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070087 /**
88 * Constructor for a given Flow Manager and Datagrid Service.
89 *
90 * @param flowManager the Flow Manager to use.
91 * @param datagridService the Datagrid Service to use.
92 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070093 FlowEventHandler(FlowManager flowManager,
94 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070095 this.flowManager = flowManager;
96 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070097 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070098 }
99
100 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800101 * Get the network topology.
102 *
103 * @return the network topology.
104 */
105 protected Topology getTopology() { return this.topology; }
106
107 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800108 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700109 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800110 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700111 //
112 // Obtain the initial Topology state
113 //
114 Collection<TopologyElement> topologyElements =
115 datagridService.getAllTopologyElements();
116 for (TopologyElement topologyElement : topologyElements) {
117 EventEntry<TopologyElement> eventEntry =
118 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
119 topologyEvents.add(eventEntry);
120 }
121 //
122 // Obtain the initial Flow Path state
123 //
124 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
125 for (FlowPath flowPath : flowPaths) {
126 EventEntry<FlowPath> eventEntry =
127 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
128 flowPathEvents.add(eventEntry);
129 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700130 //
131 // Obtain the initial FlowEntry state
132 //
133 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
134 for (FlowEntry flowEntry : flowEntries) {
135 EventEntry<FlowEntry> eventEntry =
136 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
137 flowEntryEvents.add(eventEntry);
138 }
139
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800140 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800141 synchronized (allFlowPaths) {
142 processEvents();
143 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800144 }
145
146 /**
147 * Run the thread.
148 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800149 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800150 public void run() {
151 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700152
153 //
154 // The main loop
155 //
156 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
157 try {
158 while (true) {
159 EventEntry<?> eventEntry = networkEvents.take();
160 collection.add(eventEntry);
161 networkEvents.drainTo(collection);
162
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700163 //
164 // Demultiplex all events:
165 // - EventEntry<TopologyElement>
166 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700167 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700168 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700169 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800170 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700171 if (event.eventData() instanceof TopologyElement) {
172 EventEntry<TopologyElement> topologyEventEntry =
173 (EventEntry<TopologyElement>)event;
174 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800175 continue;
176 }
177
178 // FlowPath event
179 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700180 EventEntry<FlowPath> flowPathEventEntry =
181 (EventEntry<FlowPath>)event;
182 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800183 continue;
184 }
185
186 // FlowEntry event
187 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700188 EventEntry<FlowEntry> flowEntryEventEntry =
189 (EventEntry<FlowEntry>)event;
190 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800191 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700192 }
193 }
194 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700195
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700196 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800197 synchronized (allFlowPaths) {
198 processEvents();
199 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700200 }
201 } catch (Exception exception) {
202 log.debug("Exception processing Network Events: ", exception);
203 }
204 }
205
206 /**
207 * Process the events (if any)
208 */
209 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800210 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700211
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700212 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
213 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700214 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700215 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700216
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800217 processFlowPathEvents();
218 processTopologyEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800219 processFlowEntryEvents();
220
221 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800222 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800223 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800224 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800225 }
226
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800227 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800228 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800229
230 // Assign missing Flow Entry IDs
231 assignFlowEntryId(modifiedFlowEntries);
232
233 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800234 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800235 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800236 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
237 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800238
239 //
240 // Remove Flow Entries that were deleted
241 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800242 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800243 flowPath.dataPath().removeDeletedFlowEntries();
244
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800245 //
246 // Check if Flow Paths have been installed into all switches,
247 // and generate the appropriate events.
248 //
249 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
250
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800251 // Cleanup
252 topologyEvents.clear();
253 flowPathEvents.clear();
254 flowEntryEvents.clear();
255 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800256 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800257 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800258 checkIfInstalledFlowPaths.clear();
259 }
260
261 /**
262 * Check if Flow Paths have been installed into all switches,
263 * and generate the appropriate events.
264 *
265 * @param flowPaths the flowPaths to process.
266 */
267 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
268 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
269
270 Kryo kryo = kryoFactory.newKryo();
271
272 for (FlowPath flowPath : flowPaths) {
273 boolean isInstalled = true;
274
275 //
276 // Check whether all Flow Entries have been installed
277 //
278 for (FlowEntry flowEntry : flowPath.flowEntries()) {
279 if (flowEntry.flowEntrySwitchState() !=
280 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
281 isInstalled = false;
282 break;
283 }
284 }
285
286 if (isInstalled) {
287 // Create a copy and add it to the list
288 FlowPath copyFlowPath = kryo.copy(flowPath);
289 installedFlowPaths.add(copyFlowPath);
290 }
291 }
292 kryoFactory.deleteKryo(kryo);
293
294 // Generate an event for the installed Flow Path.
295 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800296 }
297
298 /**
299 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800300 *
301 * @param modifiedFlowPaths the Flow Paths to process.
302 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800303 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800304 private Collection<FlowEntry> extractModifiedFlowEntries(
305 Collection<FlowPath> modifiedFlowPaths) {
306 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800307
308 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800309 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800310 for (FlowEntry flowEntry : flowPath.flowEntries()) {
311 if (flowEntry.flowEntrySwitchState() ==
312 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800313 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800314 }
315 }
316 }
317 return modifiedFlowEntries;
318 }
319
320 /**
321 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800322 *
323 * @param modifiedFlowEnries the collection of Flow Entries that need
324 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800325 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800326 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800327 if (modifiedFlowEntries.isEmpty())
328 return;
329
330 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
331
332 //
333 // Assign the Flow Entry ID only for Flow Entries for my switches
334 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800335 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800336 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
337 if (mySwitch == null)
338 continue;
339 if (! flowEntry.isValidFlowEntryId()) {
340 long id = flowManager.getNextFlowEntryId();
341 flowEntry.setFlowEntryId(new FlowEntryId(id));
342 }
343 }
344 }
345
346 /**
347 * Process the Flow Path events.
348 */
349 private void processFlowPathEvents() {
350 //
351 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700352 //
353 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
354 FlowPath flowPath = eventEntry.eventData();
355
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800356 log.debug("Flow Event: {} {}", eventEntry.eventType(),
357 flowPath.toString());
358
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700359 switch (eventEntry.eventType()) {
360 case ENTRY_ADD: {
361 //
362 // Add a new Flow Path
363 //
364 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
365 //
366 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800367 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700368 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700369 }
370
371 switch (flowPath.flowPathType()) {
372 case FP_TYPE_SHORTEST_PATH:
373 //
374 // Reset the Data Path, in case it was set already, because
375 // we are going to recompute it anyway.
376 //
377 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800378 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
379 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700380 break;
381 case FP_TYPE_EXPLICIT_PATH:
382 //
383 // Mark all Flow Entries for installation in the switches.
384 //
385 for (FlowEntry flowEntry : flowPath.flowEntries()) {
386 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
387 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800388 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700389 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800390 case FP_TYPE_UNKNOWN:
391 log.error("FlowPath event with unknown type");
392 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700393 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800394 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700395
396 break;
397 }
398
399 case ENTRY_REMOVE: {
400 //
401 // Remove an existing Flow Path.
402 //
403 // Find the Flow Path, and mark the Flow and its Flow Entries
404 // for deletion.
405 //
406 FlowPath existingFlowPath =
407 allFlowPaths.get(flowPath.flowId().value());
408 if (existingFlowPath == null)
409 continue; // Nothing to do
410
411 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
412 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
413 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
414 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
415 }
416
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800417 // Remove the Flow Path from the internal state
418 Long key = existingFlowPath.flowId().value();
419 allFlowPaths.remove(key);
420 shouldRecomputeFlowPaths.remove(key);
421 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700422
423 break;
424 }
425 }
426 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800427 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700428
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800429 /**
430 * Process the Topology events.
431 */
432 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700433 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800434 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700435 //
436 boolean isTopologyModified = false;
437 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
438 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800439
440 log.debug("Topology Event: {} {}", eventEntry.eventType(),
441 topologyElement.toString());
442
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700443 switch (eventEntry.eventType()) {
444 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700445 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700446 break;
447 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700448 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700449 break;
450 }
451 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700452 if (isTopologyModified) {
453 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800454 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700455 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800456 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700457
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800458 /**
459 * Process the Flow Entry events.
460 */
461 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800462 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800463 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800464
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700465 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800466 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700467 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800468 if (! unmatchedFlowEntryAdd.isEmpty()) {
469 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
470 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
471 flowPath = allFlowPaths.get(flowEntry.flowId().value());
472 if (flowPath == null)
473 continue;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800474 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
475 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800476 remainingUpdates.put(flowEntry.flowEntryId().value(),
477 flowEntry);
478 continue;
479 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800480 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
481 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
482 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700483 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800484 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700485 }
486
487 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800488 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700489 //
490 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
491 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800492
493 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
494 flowEntry.toString());
495
496 if ((! flowEntry.isValidFlowId()) ||
497 (! flowEntry.isValidFlowEntryId())) {
498 continue;
499 }
500
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700501 switch (eventEntry.eventType()) {
502 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800503 flowPath = allFlowPaths.get(flowEntry.flowId().value());
504 if (flowPath == null) {
505 // Flow Path not found: keep the entry for later matching
506 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
507 flowEntry);
508 break;
509 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800510 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
511 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800512 // Flow Entry not found: keep the entry for later matching
513 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
514 flowEntry);
515 break;
516 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800517 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
518 // Add the updated Flow Path to the list of updated paths
519 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
520 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700521 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800522
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700523 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800524 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
525 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800526 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800527 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800528
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800529 flowPath = allFlowPaths.get(flowEntry.flowId().value());
530 if (flowPath == null) {
531 // Flow Path not found: ignore the update
532 break;
533 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800534 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
535 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800536 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800537 break;
538 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800539 if (updateFlowEntryRemove(flowPath, localFlowEntry,
540 flowEntry)) {
541 // Add the updated Flow Path to the list of updated paths
542 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
543 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700544 break;
545 }
546 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700547 }
548
549 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800550 * Find a Flow Entry that should be updated because of an external
551 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700552 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800553 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800554 * @param newFlowEntry the FlowEntry with the new state.
555 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700556 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800557 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
558 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700559 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800560 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700561 //
562 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800563 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800564 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700565 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800566 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700567
568 //
569 // Local Flow Entry match found
570 //
571 if (localFlowEntry.isValidFlowEntryId()) {
572 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800573 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700574 //
575 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800576 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700577 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800578 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700579 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700580 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800581 return localFlowEntry;
582 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700583
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800584 return null; // Entry not found
585 }
586
587 /**
588 * Update a Flow Entry because of an external ENTRY_ADD event.
589 *
590 * @param flowPath the FlowPath for the Flow Entry to update.
591 * @param localFlowEntry the local Flow Entry to update.
592 * @param newFlowEntry the FlowEntry with the new state.
593 * @return true if the local Flow Entry was updated, otherwise false.
594 */
595 private boolean updateFlowEntryAdd(FlowPath flowPath,
596 FlowEntry localFlowEntry,
597 FlowEntry newFlowEntry) {
598 boolean updated = false;
599
600 if (localFlowEntry.flowEntryUserState() ==
601 FlowEntryUserState.FE_USER_DELETE) {
602 // Don't add-back a Flow Entry that is already deleted
603 return false;
604 }
605
606 if (! localFlowEntry.isValidFlowEntryId()) {
607 // Update the Flow Entry ID
608 FlowEntryId flowEntryId =
609 new FlowEntryId(newFlowEntry.flowEntryId().value());
610 localFlowEntry.setFlowEntryId(flowEntryId);
611 updated = true;
612 }
613
614 //
615 // Update the local Flow Entry, and keep state to check
616 // if the Flow Path has been installed.
617 //
618 if (localFlowEntry.flowEntryUserState() !=
619 newFlowEntry.flowEntryUserState()) {
620 localFlowEntry.setFlowEntryUserState(
621 newFlowEntry.flowEntryUserState());
622 updated = true;
623 }
624 if (localFlowEntry.flowEntrySwitchState() !=
625 newFlowEntry.flowEntrySwitchState()) {
626 localFlowEntry.setFlowEntrySwitchState(
627 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800628 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800629 updated = true;
630 }
631
632 return updated;
633 }
634
635 /**
636 * Find a Flow Entry that should be updated because of an external
637 * ENTRY_REMOVE event.
638 *
639 * @param flowPath the FlowPath for the Flow Entry to update.
640 * @param newFlowEntry the FlowEntry with the new state.
641 * @return the Flow Entry that should be updated if found, otherwise null.
642 */
643 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
644 FlowEntry newFlowEntry) {
645 //
646 // Iterate over all Flow Entries and find a match based on
647 // the Flow Entry ID.
648 //
649 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
650 if (! localFlowEntry.isValidFlowEntryId())
651 continue;
652 if (localFlowEntry.flowEntryId().value() !=
653 newFlowEntry.flowEntryId().value()) {
654 continue;
655 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800656 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700657 }
658
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800659 return null; // Entry not found
660 }
661
662 /**
663 * Update a Flow Entry because of an external ENTRY_REMOVE event.
664 *
665 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800666 * @param localFlowEntry the local Flow Entry to update.
667 * @param newFlowEntry the FlowEntry with the new state.
668 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800669 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800670 private boolean updateFlowEntryRemove(FlowPath flowPath,
671 FlowEntry localFlowEntry,
672 FlowEntry newFlowEntry) {
673 boolean updated = false;
674
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800675 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800676 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800677 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800678 if (localFlowEntry.flowEntryUserState() !=
679 newFlowEntry.flowEntryUserState()) {
680 localFlowEntry.setFlowEntryUserState(
681 newFlowEntry.flowEntryUserState());
682 updated = true;
683 }
684 if (localFlowEntry.flowEntrySwitchState() !=
685 newFlowEntry.flowEntrySwitchState()) {
686 localFlowEntry.setFlowEntrySwitchState(
687 newFlowEntry.flowEntrySwitchState());
688 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800689 }
690
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800691 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700692 }
693
694 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700695 * Recompute a Flow Path.
696 *
697 * @param flowPath the Flow Path to recompute.
698 * @return true if the recomputed Flow Path has changed, otherwise false.
699 */
700 private boolean recomputeFlowPath(FlowPath flowPath) {
701 boolean hasChanged = false;
702
703 //
704 // Test whether the Flow Path needs to be recomputed
705 //
706 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700707 case FP_TYPE_UNKNOWN:
708 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700709 case FP_TYPE_SHORTEST_PATH:
710 break;
711 case FP_TYPE_EXPLICIT_PATH:
712 return false; // An explicit path never changes
713 }
714
715 DataPath oldDataPath = flowPath.dataPath();
716
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700717 // Compute the new path
718 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
719 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700720 if (newDataPath == null) {
721 // We need the DataPath to compare the paths
722 newDataPath = new DataPath();
723 }
724 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
725
726 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700727 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700728 //
729 if (oldDataPath.flowEntries().size() !=
730 newDataPath.flowEntries().size()) {
731 hasChanged = true;
732 } else {
733 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
734 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
735 while (oldIter.hasNext() && newIter.hasNext()) {
736 FlowEntry oldFlowEntry = oldIter.next();
737 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700738 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
739 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700740 hasChanged = true;
741 break;
742 }
743 }
744 }
745 if (! hasChanged)
746 return hasChanged;
747
748 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700749 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700750 // - If a Flow Entry for a switch is in the old data path, but not
751 // in the new data path, then mark it for deletion.
752 // - If a Flow Entry for a switch is in the new data path, but not
753 // in the old data path, then mark it for addition.
754 // - If a Flow Entry for a switch is in both the old and the new
755 // data path, but it has changed, e.g., the incoming and/or outgoing
756 // port(s), then mark the old Flow Entry for deletion, and mark
757 // the new Flow Entry for addition.
758 // - If a Flow Entry for a switch is in both the old and the new
759 // data path, and it hasn't changed, then just keep it.
760 //
761 // NOTE: We use the Switch DPID of each entry to match the entries
762 //
763 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
764 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
765 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
766 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
767
768 // Prepare maps with the Flow Entries, so they are fast to lookup
769 for (FlowEntry flowEntry : oldDataPath.flowEntries())
770 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
771 for (FlowEntry flowEntry : newDataPath.flowEntries())
772 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
773
774 //
775 // Find the old Flow Entries that should be deleted
776 //
777 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
778 FlowEntry newFlowEntry =
779 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
780 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800781 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700782 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
783 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
784 deletedFlowEntries.add(oldFlowEntry);
785 }
786 }
787
788 //
789 // Find the new Flow Entries that should be added or updated
790 //
791 int idx = 0;
792 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
793 FlowEntry oldFlowEntry =
794 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
795
796 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700797 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
798 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700799 //
800 // Both Flow Entries are same
801 //
802 finalFlowEntries.add(oldFlowEntry);
803 idx++;
804 continue;
805 }
806
807 if (oldFlowEntry != null) {
808 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800809 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700810 //
811 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
812 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
813 deletedFlowEntries.add(oldFlowEntry);
814 }
815
816 //
817 // Add the new Flow Entry
818 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700819 //
820 // NOTE: Assign only the Flow ID.
821 // The Flow Entry ID is assigned later only for the Flow Entries
822 // this instance is responsible for.
823 //
824 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700825
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800826 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800827 // Copy the Flow timeouts
828 //
829 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
830 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
831
832 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800833 // Allocate the FlowEntryMatch by copying the default one
834 // from the FlowPath (if set).
835 //
836 FlowEntryMatch flowEntryMatch = null;
837 if (flowPath.flowEntryMatch() != null)
838 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
839 else
840 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700841 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800842
843 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700844 flowEntryMatch.enableInPort(newFlowEntry.inPort());
845
846 //
847 // Set the actions:
848 // If the first Flow Entry, copy the Flow Path actions to it.
849 //
850 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
851 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
852 FlowEntryActions flowActions =
853 new FlowEntryActions(flowPath.flowEntryActions());
854 for (FlowEntryAction action : flowActions.actions())
855 flowEntryActions.addAction(action);
856 }
857 idx++;
858
859 //
860 // Add the outgoing port output action
861 //
862 FlowEntryAction flowEntryAction = new FlowEntryAction();
863 flowEntryAction.setActionOutput(newFlowEntry.outPort());
864 flowEntryActions.addAction(flowEntryAction);
865
866 //
867 // Set the state of the new Flow Entry
868 //
869 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
870 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
871 finalFlowEntries.add(newFlowEntry);
872 }
873
874 //
875 // Replace the old Flow Entries with the new Flow Entries.
876 // Note that the Flow Entries that will be deleted are added at
877 // the end.
878 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800879 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700880 flowPath.dataPath().setFlowEntries(finalFlowEntries);
881
882 return hasChanged;
883 }
884
885 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700886 * Receive a notification that a Flow is added.
887 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700888 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700889 */
890 @Override
891 public void notificationRecvFlowAdded(FlowPath flowPath) {
892 EventEntry<FlowPath> eventEntry =
893 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
894 networkEvents.add(eventEntry);
895 }
896
897 /**
898 * Receive a notification that a Flow is removed.
899 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700900 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700901 */
902 @Override
903 public void notificationRecvFlowRemoved(FlowPath flowPath) {
904 EventEntry<FlowPath> eventEntry =
905 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
906 networkEvents.add(eventEntry);
907 }
908
909 /**
910 * Receive a notification that a Flow is updated.
911 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700912 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700913 */
914 @Override
915 public void notificationRecvFlowUpdated(FlowPath flowPath) {
916 // NOTE: The ADD and UPDATE events are processed in same way
917 EventEntry<FlowPath> eventEntry =
918 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
919 networkEvents.add(eventEntry);
920 }
921
922 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700923 * Receive a notification that a FlowEntry is added.
924 *
925 * @param flowEntry the FlowEntry that is added.
926 */
927 @Override
928 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
929 EventEntry<FlowEntry> eventEntry =
930 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
931 networkEvents.add(eventEntry);
932 }
933
934 /**
935 * Receive a notification that a FlowEntry is removed.
936 *
937 * @param flowEntry the FlowEntry that is removed.
938 */
939 @Override
940 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
941 EventEntry<FlowEntry> eventEntry =
942 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
943 networkEvents.add(eventEntry);
944 }
945
946 /**
947 * Receive a notification that a FlowEntry is updated.
948 *
949 * @param flowEntry the FlowEntry that is updated.
950 */
951 @Override
952 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
953 // NOTE: The ADD and UPDATE events are processed in same way
954 EventEntry<FlowEntry> eventEntry =
955 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
956 networkEvents.add(eventEntry);
957 }
958
959 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700960 * Receive a notification that a Topology Element is added.
961 *
962 * @param topologyElement the Topology Element that is added.
963 */
964 @Override
965 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
966 EventEntry<TopologyElement> eventEntry =
967 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
968 networkEvents.add(eventEntry);
969 }
970
971 /**
972 * Receive a notification that a Topology Element is removed.
973 *
974 * @param topologyElement the Topology Element that is removed.
975 */
976 @Override
977 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
978 EventEntry<TopologyElement> eventEntry =
979 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
980 networkEvents.add(eventEntry);
981 }
982
983 /**
984 * Receive a notification that a Topology Element is updated.
985 *
986 * @param topologyElement the Topology Element that is updated.
987 */
988 @Override
989 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
990 // NOTE: The ADD and UPDATE events are processed in same way
991 EventEntry<TopologyElement> eventEntry =
992 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
993 networkEvents.add(eventEntry);
994 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800995
996 /**
997 * Get a sorted copy of all Flow Paths.
998 *
999 * @return a sorted copy of all Flow Paths.
1000 */
1001 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1002 SortedMap<Long, FlowPath> sortedFlowPaths =
1003 new TreeMap<Long, FlowPath>();
1004
1005 //
1006 // TODO: For now we use serialization/deserialization to create
1007 // a copy of each Flow Path. In the future, we should use proper
1008 // copy constructors.
1009 //
1010 Kryo kryo = kryoFactory.newKryo();
1011 synchronized (allFlowPaths) {
1012 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1013 FlowPath origFlowPath = entry.getValue();
1014 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1015 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1016 }
1017 }
1018 kryoFactory.deleteKryo(kryo);
1019
1020 return sortedFlowPaths;
1021 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001022}