blob: 0a6cd76dc24accda2a22645719a19f51b7a9a920 [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 Radoslavov6b79f2b2013-10-26 21:31:10 -0700110 // Process the events (if any)
111 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
173 switch (eventEntry.eventType()) {
174 case ENTRY_ADD: {
175 //
176 // Add a new Flow Path
177 //
178 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
179 //
180 // TODO: What to do if the Flow Path already exists?
181 // Remove and then re-add it, or merge the info?
182 // For now, we don't have to do anything.
183 //
184 break;
185 }
186
187 switch (flowPath.flowPathType()) {
188 case FP_TYPE_SHORTEST_PATH:
189 //
190 // Reset the Data Path, in case it was set already, because
191 // we are going to recompute it anyway.
192 //
193 flowPath.flowEntries().clear();
194 recomputeFlowPaths.add(flowPath);
195 break;
196 case FP_TYPE_EXPLICIT_PATH:
197 //
198 // Mark all Flow Entries for installation in the switches.
199 //
200 for (FlowEntry flowEntry : flowPath.flowEntries()) {
201 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
202 }
203 modifiedFlowPaths.add(flowPath);
204 break;
205 }
206 newFlowPaths.add(flowPath);
207
208 break;
209 }
210
211 case ENTRY_REMOVE: {
212 //
213 // Remove an existing Flow Path.
214 //
215 // Find the Flow Path, and mark the Flow and its Flow Entries
216 // for deletion.
217 //
218 FlowPath existingFlowPath =
219 allFlowPaths.get(flowPath.flowId().value());
220 if (existingFlowPath == null)
221 continue; // Nothing to do
222
223 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
224 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
225 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
226 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
227 }
228
Yuta HIGUCHI2b5d0712013-10-30 15:48:13 -0700229 allFlowPaths.remove(existingFlowPath.flowId().value());
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700230 modifiedFlowPaths.add(existingFlowPath);
231
232 break;
233 }
234 }
235 }
236
237 //
238 // Process the topology events
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700239 //
240 boolean isTopologyModified = false;
241 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
242 TopologyElement topologyElement = eventEntry.eventData();
243 switch (eventEntry.eventType()) {
244 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700245 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700246 break;
247 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700248 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700249 break;
250 }
251 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700252 if (isTopologyModified) {
253 // TODO: For now, if the topology changes, we recompute all Flows
254 recomputeFlowPaths.addAll(allFlowPaths.values());
255 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700256
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700257 // Add all new Flows
258 for (FlowPath flowPath : newFlowPaths) {
259 allFlowPaths.put(flowPath.flowId().value(), flowPath);
260 }
261
262 // Recompute all affected Flow Paths and keep only the modified
263 for (FlowPath flowPath : recomputeFlowPaths) {
264 if (recomputeFlowPath(flowPath))
265 modifiedFlowPaths.add(flowPath);
266 }
267
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700268 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700269 // Process previously unmatched Flow Entry updates
270 //
271 if ((! flowPathEvents.isEmpty()) && (! unmatchedFlowEntryUpdates.isEmpty())) {
272 List<FlowEntry> remainingUpdates = new LinkedList<FlowEntry>();
273 for (FlowEntry flowEntry : unmatchedFlowEntryUpdates) {
274 if (! updateFlowEntry(flowEntry))
275 remainingUpdates.add(flowEntry);
276 }
277 unmatchedFlowEntryUpdates = remainingUpdates;
278 }
279
280 //
281 // Process the Flow Entry events
282 //
283 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
284 FlowEntry flowEntry = eventEntry.eventData();
285 switch (eventEntry.eventType()) {
286 case ENTRY_ADD:
287 //
288 // Find the corresponding Flow Entry and update it.
289 // If not found, then keep it in a local cache for
290 // later matching.
291 //
292 if (! updateFlowEntry(flowEntry))
293 unmatchedFlowEntryUpdates.add(flowEntry);
294 break;
295 case ENTRY_REMOVE:
296 //
297 // NOTE: For now we remove the Flow Entries based on
298 // local decisions, so no need to remove them because of an
299 // external event.
300 //
301 break;
302 }
303 }
304
305 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700306 // Push the Flow Entries that have been modified
307 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700308 flowManager.pushModifiedFlowEntries(modifiedFlowPaths);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700309
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700310 // Cleanup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700311 topologyEvents.clear();
312 flowPathEvents.clear();
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700313 flowEntryEvents.clear();
314 }
315
316 /**
317 * Update a Flow Entry because of an external event.
318 *
319 * @param flowEntry the FlowEntry with the new state.
320 * @return true if the Flow Entry was found and updated, otherwise false.
321 */
322 private boolean updateFlowEntry(FlowEntry flowEntry) {
323 if ((! flowEntry.isValidFlowId()) ||
324 (! flowEntry.isValidFlowEntryId())) {
325 //
326 // Ignore events for Flow Entries with invalid Flow ID or
327 // Flow Entry ID.
328 // This shouldn't happen.
329 //
330 return true;
331 }
332
333 FlowPath flowPath = allFlowPaths.get(flowEntry.flowId().value());
334 if (flowPath == null)
335 return false;
336
337 //
338 // Iterate over all Flow Entries and find a match based on the DPID
339 //
340 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
341 if (localFlowEntry.dpid().value() != flowEntry.dpid().value())
342 continue;
343 //
344 // TODO: We might want to check the FlowEntryMatch and
345 // FlowEntryActions to double-check it is the same Flow Entry
346 //
347
348 //
349 // Local Flow Entry match found
350 //
351 if (localFlowEntry.isValidFlowEntryId()) {
352 if (localFlowEntry.flowEntryId().value() !=
353 flowEntry.flowEntryId().value()) {
354 //
355 // Find a local Flow Entry, but the Flow Entry ID doesn't
356 // match. Ignore the event.
357 //
358 return true;
359 }
360 } else {
361 // Update the Flow Entry ID
362 FlowEntryId flowEntryId =
363 new FlowEntryId(flowEntry.flowEntryId().value());
364 localFlowEntry.setFlowEntryId(flowEntryId);
365 }
366
367 //
368 // Update the local Flow Entry.
369 // For now we update only the Flow Entry Switch State
370 //
371 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
372 return true;
373 }
374
375 return false; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700376 }
377
378 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700379 * Recompute a Flow Path.
380 *
381 * @param flowPath the Flow Path to recompute.
382 * @return true if the recomputed Flow Path has changed, otherwise false.
383 */
384 private boolean recomputeFlowPath(FlowPath flowPath) {
385 boolean hasChanged = false;
386
387 //
388 // Test whether the Flow Path needs to be recomputed
389 //
390 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700391 case FP_TYPE_UNKNOWN:
392 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700393 case FP_TYPE_SHORTEST_PATH:
394 break;
395 case FP_TYPE_EXPLICIT_PATH:
396 return false; // An explicit path never changes
397 }
398
399 DataPath oldDataPath = flowPath.dataPath();
400
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700401 // Compute the new path
402 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
403 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700404 if (newDataPath == null) {
405 // We need the DataPath to compare the paths
406 newDataPath = new DataPath();
407 }
408 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
409
410 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700411 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700412 //
413 if (oldDataPath.flowEntries().size() !=
414 newDataPath.flowEntries().size()) {
415 hasChanged = true;
416 } else {
417 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
418 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
419 while (oldIter.hasNext() && newIter.hasNext()) {
420 FlowEntry oldFlowEntry = oldIter.next();
421 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700422 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
423 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700424 hasChanged = true;
425 break;
426 }
427 }
428 }
429 if (! hasChanged)
430 return hasChanged;
431
432 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700433 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700434 // - If a Flow Entry for a switch is in the old data path, but not
435 // in the new data path, then mark it for deletion.
436 // - If a Flow Entry for a switch is in the new data path, but not
437 // in the old data path, then mark it for addition.
438 // - If a Flow Entry for a switch is in both the old and the new
439 // data path, but it has changed, e.g., the incoming and/or outgoing
440 // port(s), then mark the old Flow Entry for deletion, and mark
441 // the new Flow Entry for addition.
442 // - If a Flow Entry for a switch is in both the old and the new
443 // data path, and it hasn't changed, then just keep it.
444 //
445 // NOTE: We use the Switch DPID of each entry to match the entries
446 //
447 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
448 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
449 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
450 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
451
452 // Prepare maps with the Flow Entries, so they are fast to lookup
453 for (FlowEntry flowEntry : oldDataPath.flowEntries())
454 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
455 for (FlowEntry flowEntry : newDataPath.flowEntries())
456 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
457
458 //
459 // Find the old Flow Entries that should be deleted
460 //
461 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
462 FlowEntry newFlowEntry =
463 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
464 if (newFlowEntry == null) {
465 // The old Flow Entry should be deleted
466 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
467 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
468 deletedFlowEntries.add(oldFlowEntry);
469 }
470 }
471
472 //
473 // Find the new Flow Entries that should be added or updated
474 //
475 int idx = 0;
476 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
477 FlowEntry oldFlowEntry =
478 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
479
480 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700481 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
482 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700483 //
484 // Both Flow Entries are same
485 //
486 finalFlowEntries.add(oldFlowEntry);
487 idx++;
488 continue;
489 }
490
491 if (oldFlowEntry != null) {
492 //
493 // The old Flow Entry should be deleted
494 //
495 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
496 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
497 deletedFlowEntries.add(oldFlowEntry);
498 }
499
500 //
501 // Add the new Flow Entry
502 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700503 //
504 // NOTE: Assign only the Flow ID.
505 // The Flow Entry ID is assigned later only for the Flow Entries
506 // this instance is responsible for.
507 //
508 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700509
510 // Set the incoming port matching
511 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
512 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
513 flowEntryMatch.enableInPort(newFlowEntry.inPort());
514
515 //
516 // Set the actions:
517 // If the first Flow Entry, copy the Flow Path actions to it.
518 //
519 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
520 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
521 FlowEntryActions flowActions =
522 new FlowEntryActions(flowPath.flowEntryActions());
523 for (FlowEntryAction action : flowActions.actions())
524 flowEntryActions.addAction(action);
525 }
526 idx++;
527
528 //
529 // Add the outgoing port output action
530 //
531 FlowEntryAction flowEntryAction = new FlowEntryAction();
532 flowEntryAction.setActionOutput(newFlowEntry.outPort());
533 flowEntryActions.addAction(flowEntryAction);
534
535 //
536 // Set the state of the new Flow Entry
537 //
538 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
539 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
540 finalFlowEntries.add(newFlowEntry);
541 }
542
543 //
544 // Replace the old Flow Entries with the new Flow Entries.
545 // Note that the Flow Entries that will be deleted are added at
546 // the end.
547 //
548 for (FlowEntry flowEntry : deletedFlowEntries)
549 finalFlowEntries.add(flowEntry);
550 flowPath.dataPath().setFlowEntries(finalFlowEntries);
551
552 return hasChanged;
553 }
554
555 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700556 * Receive a notification that a Flow is added.
557 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700558 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700559 */
560 @Override
561 public void notificationRecvFlowAdded(FlowPath flowPath) {
562 EventEntry<FlowPath> eventEntry =
563 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
564 networkEvents.add(eventEntry);
565 }
566
567 /**
568 * Receive a notification that a Flow is removed.
569 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700570 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700571 */
572 @Override
573 public void notificationRecvFlowRemoved(FlowPath flowPath) {
574 EventEntry<FlowPath> eventEntry =
575 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
576 networkEvents.add(eventEntry);
577 }
578
579 /**
580 * Receive a notification that a Flow is updated.
581 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700582 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700583 */
584 @Override
585 public void notificationRecvFlowUpdated(FlowPath flowPath) {
586 // NOTE: The ADD and UPDATE events are processed in same way
587 EventEntry<FlowPath> eventEntry =
588 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
589 networkEvents.add(eventEntry);
590 }
591
592 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700593 * Receive a notification that a FlowEntry is added.
594 *
595 * @param flowEntry the FlowEntry that is added.
596 */
597 @Override
598 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
599 EventEntry<FlowEntry> eventEntry =
600 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
601 networkEvents.add(eventEntry);
602 }
603
604 /**
605 * Receive a notification that a FlowEntry is removed.
606 *
607 * @param flowEntry the FlowEntry that is removed.
608 */
609 @Override
610 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
611 EventEntry<FlowEntry> eventEntry =
612 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
613 networkEvents.add(eventEntry);
614 }
615
616 /**
617 * Receive a notification that a FlowEntry is updated.
618 *
619 * @param flowEntry the FlowEntry that is updated.
620 */
621 @Override
622 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
623 // NOTE: The ADD and UPDATE events are processed in same way
624 EventEntry<FlowEntry> eventEntry =
625 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
626 networkEvents.add(eventEntry);
627 }
628
629 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700630 * Receive a notification that a Topology Element is added.
631 *
632 * @param topologyElement the Topology Element that is added.
633 */
634 @Override
635 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
636 EventEntry<TopologyElement> eventEntry =
637 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
638 networkEvents.add(eventEntry);
639 }
640
641 /**
642 * Receive a notification that a Topology Element is removed.
643 *
644 * @param topologyElement the Topology Element that is removed.
645 */
646 @Override
647 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
648 EventEntry<TopologyElement> eventEntry =
649 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
650 networkEvents.add(eventEntry);
651 }
652
653 /**
654 * Receive a notification that a Topology Element is updated.
655 *
656 * @param topologyElement the Topology Element that is updated.
657 */
658 @Override
659 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
660 // NOTE: The ADD and UPDATE events are processed in same way
661 EventEntry<TopologyElement> eventEntry =
662 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
663 networkEvents.add(eventEntry);
664 }
665}