blob: cb1e678a79a5e98e4454efc1dd87b7486bbe7f70 [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 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -080077 * Get the network topology.
78 *
79 * @return the network topology.
80 */
81 protected Topology getTopology() { return this.topology; }
82
83 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070084 * Run the thread.
85 */
86 @Override
87 public void run() {
88 //
89 // Obtain the initial Topology state
90 //
91 Collection<TopologyElement> topologyElements =
92 datagridService.getAllTopologyElements();
93 for (TopologyElement topologyElement : topologyElements) {
94 EventEntry<TopologyElement> eventEntry =
95 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
96 topologyEvents.add(eventEntry);
97 }
98 //
99 // Obtain the initial Flow Path state
100 //
101 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
102 for (FlowPath flowPath : flowPaths) {
103 EventEntry<FlowPath> eventEntry =
104 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
105 flowPathEvents.add(eventEntry);
106 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700107 //
108 // Obtain the initial FlowEntry state
109 //
110 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
111 for (FlowEntry flowEntry : flowEntries) {
112 EventEntry<FlowEntry> eventEntry =
113 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
114 flowEntryEvents.add(eventEntry);
115 }
116
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800117 // Process the initial events (if any)
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700118 processEvents();
119
120 //
121 // The main loop
122 //
123 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
124 try {
125 while (true) {
126 EventEntry<?> eventEntry = networkEvents.take();
127 collection.add(eventEntry);
128 networkEvents.drainTo(collection);
129
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700130 //
131 // Demultiplex all events:
132 // - EventEntry<TopologyElement>
133 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700134 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700135 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700136 for (EventEntry<?> event : collection) {
137 if (event.eventData() instanceof TopologyElement) {
138 EventEntry<TopologyElement> topologyEventEntry =
139 (EventEntry<TopologyElement>)event;
140 topologyEvents.add(topologyEventEntry);
141 } else if (event.eventData() instanceof FlowPath) {
142 EventEntry<FlowPath> flowPathEventEntry =
143 (EventEntry<FlowPath>)event;
144 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700145 } else if (event.eventData() instanceof FlowEntry) {
146 EventEntry<FlowEntry> flowEntryEventEntry =
147 (EventEntry<FlowEntry>)event;
148 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700149 }
150 }
151 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700152
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700153 // Process the events (if any)
154 processEvents();
155 }
156 } catch (Exception exception) {
157 log.debug("Exception processing Network Events: ", exception);
158 }
159 }
160
161 /**
162 * Process the events (if any)
163 */
164 private void processEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700165 List<FlowPath> newFlowPaths = new LinkedList<FlowPath>();
166 List<FlowPath> recomputeFlowPaths = new LinkedList<FlowPath>();
167 List<FlowPath> modifiedFlowPaths = new LinkedList<FlowPath>();
168
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700169 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
170 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700171 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700172 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700173
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700174 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700175 // Process the Flow Path events
176 //
177 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
178 FlowPath flowPath = eventEntry.eventData();
179
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800180 log.debug("Flow Event: {} {}", eventEntry.eventType(),
181 flowPath.toString());
182
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700183 switch (eventEntry.eventType()) {
184 case ENTRY_ADD: {
185 //
186 // Add a new Flow Path
187 //
188 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
189 //
190 // TODO: What to do if the Flow Path already exists?
191 // Remove and then re-add it, or merge the info?
192 // For now, we don't have to do anything.
193 //
194 break;
195 }
196
197 switch (flowPath.flowPathType()) {
198 case FP_TYPE_SHORTEST_PATH:
199 //
200 // Reset the Data Path, in case it was set already, because
201 // we are going to recompute it anyway.
202 //
203 flowPath.flowEntries().clear();
204 recomputeFlowPaths.add(flowPath);
205 break;
206 case FP_TYPE_EXPLICIT_PATH:
207 //
208 // Mark all Flow Entries for installation in the switches.
209 //
210 for (FlowEntry flowEntry : flowPath.flowEntries()) {
211 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
212 }
213 modifiedFlowPaths.add(flowPath);
214 break;
215 }
216 newFlowPaths.add(flowPath);
217
218 break;
219 }
220
221 case ENTRY_REMOVE: {
222 //
223 // Remove an existing Flow Path.
224 //
225 // Find the Flow Path, and mark the Flow and its Flow Entries
226 // for deletion.
227 //
228 FlowPath existingFlowPath =
229 allFlowPaths.get(flowPath.flowId().value());
230 if (existingFlowPath == null)
231 continue; // Nothing to do
232
233 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
234 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
235 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
236 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
237 }
238
Yuta HIGUCHI2b5d0712013-10-30 15:48:13 -0700239 allFlowPaths.remove(existingFlowPath.flowId().value());
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700240 modifiedFlowPaths.add(existingFlowPath);
241
242 break;
243 }
244 }
245 }
246
247 //
248 // Process the topology events
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700249 //
250 boolean isTopologyModified = false;
251 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
252 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800253
254 log.debug("Topology Event: {} {}", eventEntry.eventType(),
255 topologyElement.toString());
256
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700257 switch (eventEntry.eventType()) {
258 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700259 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700260 break;
261 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700262 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700263 break;
264 }
265 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700266 if (isTopologyModified) {
267 // TODO: For now, if the topology changes, we recompute all Flows
268 recomputeFlowPaths.addAll(allFlowPaths.values());
269 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700270
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700271 // Add all new Flows
272 for (FlowPath flowPath : newFlowPaths) {
273 allFlowPaths.put(flowPath.flowId().value(), flowPath);
274 }
275
276 // Recompute all affected Flow Paths and keep only the modified
277 for (FlowPath flowPath : recomputeFlowPaths) {
278 if (recomputeFlowPath(flowPath))
279 modifiedFlowPaths.add(flowPath);
280 }
281
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700282 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700283 // Process previously unmatched Flow Entry updates
284 //
285 if ((! flowPathEvents.isEmpty()) && (! unmatchedFlowEntryUpdates.isEmpty())) {
286 List<FlowEntry> remainingUpdates = new LinkedList<FlowEntry>();
287 for (FlowEntry flowEntry : unmatchedFlowEntryUpdates) {
288 if (! updateFlowEntry(flowEntry))
289 remainingUpdates.add(flowEntry);
290 }
291 unmatchedFlowEntryUpdates = remainingUpdates;
292 }
293
294 //
295 // Process the Flow Entry events
296 //
297 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
298 FlowEntry flowEntry = eventEntry.eventData();
299 switch (eventEntry.eventType()) {
300 case ENTRY_ADD:
301 //
302 // Find the corresponding Flow Entry and update it.
303 // If not found, then keep it in a local cache for
304 // later matching.
305 //
306 if (! updateFlowEntry(flowEntry))
307 unmatchedFlowEntryUpdates.add(flowEntry);
308 break;
309 case ENTRY_REMOVE:
310 //
311 // NOTE: For now we remove the Flow Entries based on
312 // local decisions, so no need to remove them because of an
313 // external event.
314 //
315 break;
316 }
317 }
318
319 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700320 // Push the Flow Entries that have been modified
321 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700322 flowManager.pushModifiedFlowEntries(modifiedFlowPaths);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700323
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700324 // Cleanup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700325 topologyEvents.clear();
326 flowPathEvents.clear();
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700327 flowEntryEvents.clear();
328 }
329
330 /**
331 * Update a Flow Entry because of an external event.
332 *
333 * @param flowEntry the FlowEntry with the new state.
334 * @return true if the Flow Entry was found and updated, otherwise false.
335 */
336 private boolean updateFlowEntry(FlowEntry flowEntry) {
337 if ((! flowEntry.isValidFlowId()) ||
338 (! flowEntry.isValidFlowEntryId())) {
339 //
340 // Ignore events for Flow Entries with invalid Flow ID or
341 // Flow Entry ID.
342 // This shouldn't happen.
343 //
344 return true;
345 }
346
347 FlowPath flowPath = allFlowPaths.get(flowEntry.flowId().value());
348 if (flowPath == null)
349 return false;
350
351 //
352 // Iterate over all Flow Entries and find a match based on the DPID
353 //
354 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
355 if (localFlowEntry.dpid().value() != flowEntry.dpid().value())
356 continue;
357 //
358 // TODO: We might want to check the FlowEntryMatch and
359 // FlowEntryActions to double-check it is the same Flow Entry
360 //
361
362 //
363 // Local Flow Entry match found
364 //
365 if (localFlowEntry.isValidFlowEntryId()) {
366 if (localFlowEntry.flowEntryId().value() !=
367 flowEntry.flowEntryId().value()) {
368 //
369 // Find a local Flow Entry, but the Flow Entry ID doesn't
370 // match. Ignore the event.
371 //
372 return true;
373 }
374 } else {
375 // Update the Flow Entry ID
376 FlowEntryId flowEntryId =
377 new FlowEntryId(flowEntry.flowEntryId().value());
378 localFlowEntry.setFlowEntryId(flowEntryId);
379 }
380
381 //
382 // Update the local Flow Entry.
383 // For now we update only the Flow Entry Switch State
384 //
385 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
386 return true;
387 }
388
389 return false; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700390 }
391
392 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700393 * Recompute a Flow Path.
394 *
395 * @param flowPath the Flow Path to recompute.
396 * @return true if the recomputed Flow Path has changed, otherwise false.
397 */
398 private boolean recomputeFlowPath(FlowPath flowPath) {
399 boolean hasChanged = false;
400
401 //
402 // Test whether the Flow Path needs to be recomputed
403 //
404 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700405 case FP_TYPE_UNKNOWN:
406 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700407 case FP_TYPE_SHORTEST_PATH:
408 break;
409 case FP_TYPE_EXPLICIT_PATH:
410 return false; // An explicit path never changes
411 }
412
413 DataPath oldDataPath = flowPath.dataPath();
414
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700415 // Compute the new path
416 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
417 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700418 if (newDataPath == null) {
419 // We need the DataPath to compare the paths
420 newDataPath = new DataPath();
421 }
422 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
423
424 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700425 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700426 //
427 if (oldDataPath.flowEntries().size() !=
428 newDataPath.flowEntries().size()) {
429 hasChanged = true;
430 } else {
431 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
432 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
433 while (oldIter.hasNext() && newIter.hasNext()) {
434 FlowEntry oldFlowEntry = oldIter.next();
435 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700436 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
437 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700438 hasChanged = true;
439 break;
440 }
441 }
442 }
443 if (! hasChanged)
444 return hasChanged;
445
446 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700447 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700448 // - If a Flow Entry for a switch is in the old data path, but not
449 // in the new data path, then mark it for deletion.
450 // - If a Flow Entry for a switch is in the new data path, but not
451 // in the old data path, then mark it for addition.
452 // - If a Flow Entry for a switch is in both the old and the new
453 // data path, but it has changed, e.g., the incoming and/or outgoing
454 // port(s), then mark the old Flow Entry for deletion, and mark
455 // the new Flow Entry for addition.
456 // - If a Flow Entry for a switch is in both the old and the new
457 // data path, and it hasn't changed, then just keep it.
458 //
459 // NOTE: We use the Switch DPID of each entry to match the entries
460 //
461 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
462 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
463 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
464 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
465
466 // Prepare maps with the Flow Entries, so they are fast to lookup
467 for (FlowEntry flowEntry : oldDataPath.flowEntries())
468 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
469 for (FlowEntry flowEntry : newDataPath.flowEntries())
470 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
471
472 //
473 // Find the old Flow Entries that should be deleted
474 //
475 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
476 FlowEntry newFlowEntry =
477 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
478 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800479 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700480 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
481 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
482 deletedFlowEntries.add(oldFlowEntry);
483 }
484 }
485
486 //
487 // Find the new Flow Entries that should be added or updated
488 //
489 int idx = 0;
490 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
491 FlowEntry oldFlowEntry =
492 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
493
494 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700495 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
496 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700497 //
498 // Both Flow Entries are same
499 //
500 finalFlowEntries.add(oldFlowEntry);
501 idx++;
502 continue;
503 }
504
505 if (oldFlowEntry != null) {
506 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800507 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700508 //
509 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
510 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
511 deletedFlowEntries.add(oldFlowEntry);
512 }
513
514 //
515 // Add the new Flow Entry
516 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700517 //
518 // NOTE: Assign only the Flow ID.
519 // The Flow Entry ID is assigned later only for the Flow Entries
520 // this instance is responsible for.
521 //
522 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700523
524 // Set the incoming port matching
525 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
526 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
527 flowEntryMatch.enableInPort(newFlowEntry.inPort());
528
529 //
530 // Set the actions:
531 // If the first Flow Entry, copy the Flow Path actions to it.
532 //
533 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
534 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
535 FlowEntryActions flowActions =
536 new FlowEntryActions(flowPath.flowEntryActions());
537 for (FlowEntryAction action : flowActions.actions())
538 flowEntryActions.addAction(action);
539 }
540 idx++;
541
542 //
543 // Add the outgoing port output action
544 //
545 FlowEntryAction flowEntryAction = new FlowEntryAction();
546 flowEntryAction.setActionOutput(newFlowEntry.outPort());
547 flowEntryActions.addAction(flowEntryAction);
548
549 //
550 // Set the state of the new Flow Entry
551 //
552 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
553 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
554 finalFlowEntries.add(newFlowEntry);
555 }
556
557 //
558 // Replace the old Flow Entries with the new Flow Entries.
559 // Note that the Flow Entries that will be deleted are added at
560 // the end.
561 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800562 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700563 flowPath.dataPath().setFlowEntries(finalFlowEntries);
564
565 return hasChanged;
566 }
567
568 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700569 * Receive a notification that a Flow is added.
570 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700571 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700572 */
573 @Override
574 public void notificationRecvFlowAdded(FlowPath flowPath) {
575 EventEntry<FlowPath> eventEntry =
576 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
577 networkEvents.add(eventEntry);
578 }
579
580 /**
581 * Receive a notification that a Flow is removed.
582 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700583 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700584 */
585 @Override
586 public void notificationRecvFlowRemoved(FlowPath flowPath) {
587 EventEntry<FlowPath> eventEntry =
588 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
589 networkEvents.add(eventEntry);
590 }
591
592 /**
593 * Receive a notification that a Flow is updated.
594 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700595 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700596 */
597 @Override
598 public void notificationRecvFlowUpdated(FlowPath flowPath) {
599 // NOTE: The ADD and UPDATE events are processed in same way
600 EventEntry<FlowPath> eventEntry =
601 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
602 networkEvents.add(eventEntry);
603 }
604
605 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700606 * Receive a notification that a FlowEntry is added.
607 *
608 * @param flowEntry the FlowEntry that is added.
609 */
610 @Override
611 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
612 EventEntry<FlowEntry> eventEntry =
613 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
614 networkEvents.add(eventEntry);
615 }
616
617 /**
618 * Receive a notification that a FlowEntry is removed.
619 *
620 * @param flowEntry the FlowEntry that is removed.
621 */
622 @Override
623 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
624 EventEntry<FlowEntry> eventEntry =
625 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
626 networkEvents.add(eventEntry);
627 }
628
629 /**
630 * Receive a notification that a FlowEntry is updated.
631 *
632 * @param flowEntry the FlowEntry that is updated.
633 */
634 @Override
635 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
636 // NOTE: The ADD and UPDATE events are processed in same way
637 EventEntry<FlowEntry> eventEntry =
638 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
639 networkEvents.add(eventEntry);
640 }
641
642 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700643 * Receive a notification that a Topology Element is added.
644 *
645 * @param topologyElement the Topology Element that is added.
646 */
647 @Override
648 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
649 EventEntry<TopologyElement> eventEntry =
650 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
651 networkEvents.add(eventEntry);
652 }
653
654 /**
655 * Receive a notification that a Topology Element is removed.
656 *
657 * @param topologyElement the Topology Element that is removed.
658 */
659 @Override
660 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
661 EventEntry<TopologyElement> eventEntry =
662 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
663 networkEvents.add(eventEntry);
664 }
665
666 /**
667 * Receive a notification that a Topology Element is updated.
668 *
669 * @param topologyElement the Topology Element that is updated.
670 */
671 @Override
672 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
673 // NOTE: The ADD and UPDATE events are processed in same way
674 EventEntry<TopologyElement> eventEntry =
675 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
676 networkEvents.add(eventEntry);
677 }
678}