blob: debb5b117a8622dff539b93153f7ff326fb23dd0 [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 Radoslavov6b79f2b2013-10-26 21:31:10 -070010import java.util.concurrent.BlockingQueue;
11import java.util.concurrent.LinkedBlockingQueue;
12
13import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070014import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070015import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070016import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070017import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070019import net.onrc.onos.ofcontroller.util.FlowEntry;
20import net.onrc.onos.ofcontroller.util.FlowEntryAction;
21import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070022import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070023import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
24import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
25import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070026import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070027import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070028import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070029
30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
33/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070034 * Class for FlowPath Maintenance.
35 * This class listens for FlowEvents to:
36 * - Maintain a local cache of the Network Topology.
37 * - Detect FlowPaths impacted by Topology change.
38 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070039 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070040class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070041 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070042 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070043
44 private FlowManager flowManager; // The Flow Manager to use
45 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070046 private Topology topology; // The network topology
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070047 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070048 private List<FlowEntry> unmatchedFlowEntryUpdates =
49 new LinkedList<FlowEntry>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070050
51 // The queue with Flow Path and Topology Element updates
52 private BlockingQueue<EventEntry<?>> networkEvents =
53 new LinkedBlockingQueue<EventEntry<?>>();
54
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070055 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070056 private List<EventEntry<TopologyElement>> topologyEvents =
57 new LinkedList<EventEntry<TopologyElement>>();
58 private List<EventEntry<FlowPath>> flowPathEvents =
59 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070060 private List<EventEntry<FlowEntry>> flowEntryEvents =
61 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070062
63 /**
64 * Constructor for a given Flow Manager and Datagrid Service.
65 *
66 * @param flowManager the Flow Manager to use.
67 * @param datagridService the Datagrid Service to use.
68 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070069 FlowEventHandler(FlowManager flowManager,
70 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070071 this.flowManager = flowManager;
72 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070073 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070074 }
75
76 /**
77 * Run the thread.
78 */
79 @Override
80 public void run() {
81 //
82 // Obtain the initial Topology state
83 //
84 Collection<TopologyElement> topologyElements =
85 datagridService.getAllTopologyElements();
86 for (TopologyElement topologyElement : topologyElements) {
87 EventEntry<TopologyElement> eventEntry =
88 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
89 topologyEvents.add(eventEntry);
90 }
91 //
92 // Obtain the initial Flow Path state
93 //
94 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
95 for (FlowPath flowPath : flowPaths) {
96 EventEntry<FlowPath> eventEntry =
97 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
98 flowPathEvents.add(eventEntry);
99 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700100 //
101 // Obtain the initial FlowEntry state
102 //
103 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
104 for (FlowEntry flowEntry : flowEntries) {
105 EventEntry<FlowEntry> eventEntry =
106 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
107 flowEntryEvents.add(eventEntry);
108 }
109
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800110 // Process the initial events (if any)
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700111 processEvents();
112
113 //
114 // The main loop
115 //
116 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
117 try {
118 while (true) {
119 EventEntry<?> eventEntry = networkEvents.take();
120 collection.add(eventEntry);
121 networkEvents.drainTo(collection);
122
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700123 //
124 // Demultiplex all events:
125 // - EventEntry<TopologyElement>
126 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700127 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700128 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700129 for (EventEntry<?> event : collection) {
130 if (event.eventData() instanceof TopologyElement) {
131 EventEntry<TopologyElement> topologyEventEntry =
132 (EventEntry<TopologyElement>)event;
133 topologyEvents.add(topologyEventEntry);
134 } else if (event.eventData() instanceof FlowPath) {
135 EventEntry<FlowPath> flowPathEventEntry =
136 (EventEntry<FlowPath>)event;
137 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700138 } else if (event.eventData() instanceof FlowEntry) {
139 EventEntry<FlowEntry> flowEntryEventEntry =
140 (EventEntry<FlowEntry>)event;
141 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700142 }
143 }
144 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700145
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700146 // Process the events (if any)
147 processEvents();
148 }
149 } catch (Exception exception) {
150 log.debug("Exception processing Network Events: ", exception);
151 }
152 }
153
154 /**
155 * Process the events (if any)
156 */
157 private void processEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700158 List<FlowPath> newFlowPaths = new LinkedList<FlowPath>();
159 List<FlowPath> recomputeFlowPaths = new LinkedList<FlowPath>();
160 List<FlowPath> modifiedFlowPaths = new LinkedList<FlowPath>();
161
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700162 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
163 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700164 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700165 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700166
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700167 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700168 // Process the Flow Path events
169 //
170 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
171 FlowPath flowPath = eventEntry.eventData();
172
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800173 log.debug("Flow Event: {} {}", eventEntry.eventType(),
174 flowPath.toString());
175
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700176 switch (eventEntry.eventType()) {
177 case ENTRY_ADD: {
178 //
179 // Add a new Flow Path
180 //
181 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
182 //
183 // TODO: What to do if the Flow Path already exists?
184 // Remove and then re-add it, or merge the info?
185 // For now, we don't have to do anything.
186 //
187 break;
188 }
189
190 switch (flowPath.flowPathType()) {
191 case FP_TYPE_SHORTEST_PATH:
192 //
193 // Reset the Data Path, in case it was set already, because
194 // we are going to recompute it anyway.
195 //
196 flowPath.flowEntries().clear();
197 recomputeFlowPaths.add(flowPath);
198 break;
199 case FP_TYPE_EXPLICIT_PATH:
200 //
201 // Mark all Flow Entries for installation in the switches.
202 //
203 for (FlowEntry flowEntry : flowPath.flowEntries()) {
204 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
205 }
206 modifiedFlowPaths.add(flowPath);
207 break;
208 }
209 newFlowPaths.add(flowPath);
210
211 break;
212 }
213
214 case ENTRY_REMOVE: {
215 //
216 // Remove an existing Flow Path.
217 //
218 // Find the Flow Path, and mark the Flow and its Flow Entries
219 // for deletion.
220 //
221 FlowPath existingFlowPath =
222 allFlowPaths.get(flowPath.flowId().value());
223 if (existingFlowPath == null)
224 continue; // Nothing to do
225
226 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
227 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
228 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
229 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
230 }
231
Yuta HIGUCHI2b5d0712013-10-30 15:48:13 -0700232 allFlowPaths.remove(existingFlowPath.flowId().value());
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700233 modifiedFlowPaths.add(existingFlowPath);
234
235 break;
236 }
237 }
238 }
239
240 //
241 // Process the topology events
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700242 //
243 boolean isTopologyModified = false;
244 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
245 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800246
247 log.debug("Topology Event: {} {}", eventEntry.eventType(),
248 topologyElement.toString());
249
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700250 switch (eventEntry.eventType()) {
251 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700252 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700253 break;
254 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700255 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700256 break;
257 }
258 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700259 if (isTopologyModified) {
260 // TODO: For now, if the topology changes, we recompute all Flows
261 recomputeFlowPaths.addAll(allFlowPaths.values());
262 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700263
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700264 // Add all new Flows
265 for (FlowPath flowPath : newFlowPaths) {
266 allFlowPaths.put(flowPath.flowId().value(), flowPath);
267 }
268
269 // Recompute all affected Flow Paths and keep only the modified
270 for (FlowPath flowPath : recomputeFlowPaths) {
271 if (recomputeFlowPath(flowPath))
272 modifiedFlowPaths.add(flowPath);
273 }
274
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700275 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700276 // Process previously unmatched Flow Entry updates
277 //
278 if ((! flowPathEvents.isEmpty()) && (! unmatchedFlowEntryUpdates.isEmpty())) {
279 List<FlowEntry> remainingUpdates = new LinkedList<FlowEntry>();
280 for (FlowEntry flowEntry : unmatchedFlowEntryUpdates) {
281 if (! updateFlowEntry(flowEntry))
282 remainingUpdates.add(flowEntry);
283 }
284 unmatchedFlowEntryUpdates = remainingUpdates;
285 }
286
287 //
288 // Process the Flow Entry events
289 //
290 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
291 FlowEntry flowEntry = eventEntry.eventData();
292 switch (eventEntry.eventType()) {
293 case ENTRY_ADD:
294 //
295 // Find the corresponding Flow Entry and update it.
296 // If not found, then keep it in a local cache for
297 // later matching.
298 //
299 if (! updateFlowEntry(flowEntry))
300 unmatchedFlowEntryUpdates.add(flowEntry);
301 break;
302 case ENTRY_REMOVE:
303 //
304 // NOTE: For now we remove the Flow Entries based on
305 // local decisions, so no need to remove them because of an
306 // external event.
307 //
308 break;
309 }
310 }
311
312 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700313 // Push the Flow Entries that have been modified
314 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700315 flowManager.pushModifiedFlowEntries(modifiedFlowPaths);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700316
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700317 // Cleanup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700318 topologyEvents.clear();
319 flowPathEvents.clear();
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700320 flowEntryEvents.clear();
321 }
322
323 /**
324 * Update a Flow Entry because of an external event.
325 *
326 * @param flowEntry the FlowEntry with the new state.
327 * @return true if the Flow Entry was found and updated, otherwise false.
328 */
329 private boolean updateFlowEntry(FlowEntry flowEntry) {
330 if ((! flowEntry.isValidFlowId()) ||
331 (! flowEntry.isValidFlowEntryId())) {
332 //
333 // Ignore events for Flow Entries with invalid Flow ID or
334 // Flow Entry ID.
335 // This shouldn't happen.
336 //
337 return true;
338 }
339
340 FlowPath flowPath = allFlowPaths.get(flowEntry.flowId().value());
341 if (flowPath == null)
342 return false;
343
344 //
345 // Iterate over all Flow Entries and find a match based on the DPID
346 //
347 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
348 if (localFlowEntry.dpid().value() != flowEntry.dpid().value())
349 continue;
350 //
351 // TODO: We might want to check the FlowEntryMatch and
352 // FlowEntryActions to double-check it is the same Flow Entry
353 //
354
355 //
356 // Local Flow Entry match found
357 //
358 if (localFlowEntry.isValidFlowEntryId()) {
359 if (localFlowEntry.flowEntryId().value() !=
360 flowEntry.flowEntryId().value()) {
361 //
362 // Find a local Flow Entry, but the Flow Entry ID doesn't
363 // match. Ignore the event.
364 //
365 return true;
366 }
367 } else {
368 // Update the Flow Entry ID
369 FlowEntryId flowEntryId =
370 new FlowEntryId(flowEntry.flowEntryId().value());
371 localFlowEntry.setFlowEntryId(flowEntryId);
372 }
373
374 //
375 // Update the local Flow Entry.
376 // For now we update only the Flow Entry Switch State
377 //
378 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
379 return true;
380 }
381
382 return false; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700383 }
384
385 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700386 * Recompute a Flow Path.
387 *
388 * @param flowPath the Flow Path to recompute.
389 * @return true if the recomputed Flow Path has changed, otherwise false.
390 */
391 private boolean recomputeFlowPath(FlowPath flowPath) {
392 boolean hasChanged = false;
393
394 //
395 // Test whether the Flow Path needs to be recomputed
396 //
397 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700398 case FP_TYPE_UNKNOWN:
399 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700400 case FP_TYPE_SHORTEST_PATH:
401 break;
402 case FP_TYPE_EXPLICIT_PATH:
403 return false; // An explicit path never changes
404 }
405
406 DataPath oldDataPath = flowPath.dataPath();
407
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700408 // Compute the new path
409 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
410 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700411 if (newDataPath == null) {
412 // We need the DataPath to compare the paths
413 newDataPath = new DataPath();
414 }
415 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
416
417 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700418 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700419 //
420 if (oldDataPath.flowEntries().size() !=
421 newDataPath.flowEntries().size()) {
422 hasChanged = true;
423 } else {
424 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
425 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
426 while (oldIter.hasNext() && newIter.hasNext()) {
427 FlowEntry oldFlowEntry = oldIter.next();
428 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700429 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
430 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700431 hasChanged = true;
432 break;
433 }
434 }
435 }
436 if (! hasChanged)
437 return hasChanged;
438
439 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700440 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700441 // - If a Flow Entry for a switch is in the old data path, but not
442 // in the new data path, then mark it for deletion.
443 // - If a Flow Entry for a switch is in the new data path, but not
444 // in the old data path, then mark it for addition.
445 // - If a Flow Entry for a switch is in both the old and the new
446 // data path, but it has changed, e.g., the incoming and/or outgoing
447 // port(s), then mark the old Flow Entry for deletion, and mark
448 // the new Flow Entry for addition.
449 // - If a Flow Entry for a switch is in both the old and the new
450 // data path, and it hasn't changed, then just keep it.
451 //
452 // NOTE: We use the Switch DPID of each entry to match the entries
453 //
454 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
455 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
456 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
457 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
458
459 // Prepare maps with the Flow Entries, so they are fast to lookup
460 for (FlowEntry flowEntry : oldDataPath.flowEntries())
461 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
462 for (FlowEntry flowEntry : newDataPath.flowEntries())
463 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
464
465 //
466 // Find the old Flow Entries that should be deleted
467 //
468 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
469 FlowEntry newFlowEntry =
470 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
471 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800472 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700473 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
474 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
475 deletedFlowEntries.add(oldFlowEntry);
476 }
477 }
478
479 //
480 // Find the new Flow Entries that should be added or updated
481 //
482 int idx = 0;
483 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
484 FlowEntry oldFlowEntry =
485 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
486
487 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700488 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
489 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700490 //
491 // Both Flow Entries are same
492 //
493 finalFlowEntries.add(oldFlowEntry);
494 idx++;
495 continue;
496 }
497
498 if (oldFlowEntry != null) {
499 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800500 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700501 //
502 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
503 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
504 deletedFlowEntries.add(oldFlowEntry);
505 }
506
507 //
508 // Add the new Flow Entry
509 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700510 //
511 // NOTE: Assign only the Flow ID.
512 // The Flow Entry ID is assigned later only for the Flow Entries
513 // this instance is responsible for.
514 //
515 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700516
517 // Set the incoming port matching
518 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
519 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
520 flowEntryMatch.enableInPort(newFlowEntry.inPort());
521
522 //
523 // Set the actions:
524 // If the first Flow Entry, copy the Flow Path actions to it.
525 //
526 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
527 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
528 FlowEntryActions flowActions =
529 new FlowEntryActions(flowPath.flowEntryActions());
530 for (FlowEntryAction action : flowActions.actions())
531 flowEntryActions.addAction(action);
532 }
533 idx++;
534
535 //
536 // Add the outgoing port output action
537 //
538 FlowEntryAction flowEntryAction = new FlowEntryAction();
539 flowEntryAction.setActionOutput(newFlowEntry.outPort());
540 flowEntryActions.addAction(flowEntryAction);
541
542 //
543 // Set the state of the new Flow Entry
544 //
545 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
546 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
547 finalFlowEntries.add(newFlowEntry);
548 }
549
550 //
551 // Replace the old Flow Entries with the new Flow Entries.
552 // Note that the Flow Entries that will be deleted are added at
553 // the end.
554 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800555 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700556 flowPath.dataPath().setFlowEntries(finalFlowEntries);
557
558 return hasChanged;
559 }
560
561 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700562 * Receive a notification that a Flow is added.
563 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700564 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700565 */
566 @Override
567 public void notificationRecvFlowAdded(FlowPath flowPath) {
568 EventEntry<FlowPath> eventEntry =
569 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
570 networkEvents.add(eventEntry);
571 }
572
573 /**
574 * Receive a notification that a Flow is removed.
575 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700576 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700577 */
578 @Override
579 public void notificationRecvFlowRemoved(FlowPath flowPath) {
580 EventEntry<FlowPath> eventEntry =
581 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
582 networkEvents.add(eventEntry);
583 }
584
585 /**
586 * Receive a notification that a Flow is updated.
587 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700588 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700589 */
590 @Override
591 public void notificationRecvFlowUpdated(FlowPath flowPath) {
592 // NOTE: The ADD and UPDATE events are processed in same way
593 EventEntry<FlowPath> eventEntry =
594 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
595 networkEvents.add(eventEntry);
596 }
597
598 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700599 * Receive a notification that a FlowEntry is added.
600 *
601 * @param flowEntry the FlowEntry that is added.
602 */
603 @Override
604 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
605 EventEntry<FlowEntry> eventEntry =
606 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
607 networkEvents.add(eventEntry);
608 }
609
610 /**
611 * Receive a notification that a FlowEntry is removed.
612 *
613 * @param flowEntry the FlowEntry that is removed.
614 */
615 @Override
616 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
617 EventEntry<FlowEntry> eventEntry =
618 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
619 networkEvents.add(eventEntry);
620 }
621
622 /**
623 * Receive a notification that a FlowEntry is updated.
624 *
625 * @param flowEntry the FlowEntry that is updated.
626 */
627 @Override
628 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
629 // NOTE: The ADD and UPDATE events are processed in same way
630 EventEntry<FlowEntry> eventEntry =
631 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
632 networkEvents.add(eventEntry);
633 }
634
635 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700636 * Receive a notification that a Topology Element is added.
637 *
638 * @param topologyElement the Topology Element that is added.
639 */
640 @Override
641 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
642 EventEntry<TopologyElement> eventEntry =
643 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
644 networkEvents.add(eventEntry);
645 }
646
647 /**
648 * Receive a notification that a Topology Element is removed.
649 *
650 * @param topologyElement the Topology Element that is removed.
651 */
652 @Override
653 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
654 EventEntry<TopologyElement> eventEntry =
655 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
656 networkEvents.add(eventEntry);
657 }
658
659 /**
660 * Receive a notification that a Topology Element is updated.
661 *
662 * @param topologyElement the Topology Element that is updated.
663 */
664 @Override
665 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
666 // NOTE: The ADD and UPDATE events are processed in same way
667 EventEntry<TopologyElement> eventEntry =
668 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
669 networkEvents.add(eventEntry);
670 }
671}