blob: 23b2f28bc0d58b2051efbe62c9f550dd58198aa6 [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 -070010
11import java.util.concurrent.BlockingQueue;
12import java.util.concurrent.LinkedBlockingQueue;
13
14import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070015import net.onrc.onos.ofcontroller.topology.ShortestPath;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070016import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070017import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070018import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070019import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070020import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070021import net.onrc.onos.ofcontroller.util.FlowEntry;
22import net.onrc.onos.ofcontroller.util.FlowEntryAction;
23import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070024import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070025import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
26import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
27import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070028import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070029import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070030import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070031
32import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
35/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070036 * Class for FlowPath Maintenance.
37 * This class listens for FlowEvents to:
38 * - Maintain a local cache of the Network Topology.
39 * - Detect FlowPaths impacted by Topology change.
40 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070041 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070042class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070043 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070044 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070045
46 private FlowManager flowManager; // The Flow Manager to use
47 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070048 private Topology topology; // The network topology
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070049 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070050 private List<FlowEntry> unmatchedFlowEntryUpdates =
51 new LinkedList<FlowEntry>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070052
53 // The queue with Flow Path and Topology Element updates
54 private BlockingQueue<EventEntry<?>> networkEvents =
55 new LinkedBlockingQueue<EventEntry<?>>();
56
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070057 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070058 private List<EventEntry<TopologyElement>> topologyEvents =
59 new LinkedList<EventEntry<TopologyElement>>();
60 private List<EventEntry<FlowPath>> flowPathEvents =
61 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070062 private List<EventEntry<FlowEntry>> flowEntryEvents =
63 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070064
65 /**
66 * Constructor for a given Flow Manager and Datagrid Service.
67 *
68 * @param flowManager the Flow Manager to use.
69 * @param datagridService the Datagrid Service to use.
70 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070071 FlowEventHandler(FlowManager flowManager,
72 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070073 this.flowManager = flowManager;
74 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070075 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070076 }
77
78 /**
79 * Run the thread.
80 */
81 @Override
82 public void run() {
83 //
84 // Obtain the initial Topology state
85 //
86 Collection<TopologyElement> topologyElements =
87 datagridService.getAllTopologyElements();
88 for (TopologyElement topologyElement : topologyElements) {
89 EventEntry<TopologyElement> eventEntry =
90 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
91 topologyEvents.add(eventEntry);
92 }
93 //
94 // Obtain the initial Flow Path state
95 //
96 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
97 for (FlowPath flowPath : flowPaths) {
98 EventEntry<FlowPath> eventEntry =
99 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
100 flowPathEvents.add(eventEntry);
101 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700102 //
103 // Obtain the initial FlowEntry state
104 //
105 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
106 for (FlowEntry flowEntry : flowEntries) {
107 EventEntry<FlowEntry> eventEntry =
108 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
109 flowEntryEvents.add(eventEntry);
110 }
111
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700112 // Process the events (if any)
113 processEvents();
114
115 //
116 // The main loop
117 //
118 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
119 try {
120 while (true) {
121 EventEntry<?> eventEntry = networkEvents.take();
122 collection.add(eventEntry);
123 networkEvents.drainTo(collection);
124
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700125 //
126 // Demultiplex all events:
127 // - EventEntry<TopologyElement>
128 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700129 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700130 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700131 for (EventEntry<?> event : collection) {
132 if (event.eventData() instanceof TopologyElement) {
133 EventEntry<TopologyElement> topologyEventEntry =
134 (EventEntry<TopologyElement>)event;
135 topologyEvents.add(topologyEventEntry);
136 } else if (event.eventData() instanceof FlowPath) {
137 EventEntry<FlowPath> flowPathEventEntry =
138 (EventEntry<FlowPath>)event;
139 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700140 } else if (event.eventData() instanceof FlowEntry) {
141 EventEntry<FlowEntry> flowEntryEventEntry =
142 (EventEntry<FlowEntry>)event;
143 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700144 }
145 }
146 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700147
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700148 // Process the events (if any)
149 processEvents();
150 }
151 } catch (Exception exception) {
152 log.debug("Exception processing Network Events: ", exception);
153 }
154 }
155
156 /**
157 * Process the events (if any)
158 */
159 private void processEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700160 List<FlowPath> newFlowPaths = new LinkedList<FlowPath>();
161 List<FlowPath> recomputeFlowPaths = new LinkedList<FlowPath>();
162 List<FlowPath> modifiedFlowPaths = new LinkedList<FlowPath>();
163
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700164 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
165 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700166 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700167 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700168
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700169 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700170 // Process the Flow Path events
171 //
172 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
173 FlowPath flowPath = eventEntry.eventData();
174
175 switch (eventEntry.eventType()) {
176 case ENTRY_ADD: {
177 //
178 // Add a new Flow Path
179 //
180 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
181 //
182 // TODO: What to do if the Flow Path already exists?
183 // Remove and then re-add it, or merge the info?
184 // For now, we don't have to do anything.
185 //
186 break;
187 }
188
189 switch (flowPath.flowPathType()) {
190 case FP_TYPE_SHORTEST_PATH:
191 //
192 // Reset the Data Path, in case it was set already, because
193 // we are going to recompute it anyway.
194 //
195 flowPath.flowEntries().clear();
196 recomputeFlowPaths.add(flowPath);
197 break;
198 case FP_TYPE_EXPLICIT_PATH:
199 //
200 // Mark all Flow Entries for installation in the switches.
201 //
202 for (FlowEntry flowEntry : flowPath.flowEntries()) {
203 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
204 }
205 modifiedFlowPaths.add(flowPath);
206 break;
207 }
208 newFlowPaths.add(flowPath);
209
210 break;
211 }
212
213 case ENTRY_REMOVE: {
214 //
215 // Remove an existing Flow Path.
216 //
217 // Find the Flow Path, and mark the Flow and its Flow Entries
218 // for deletion.
219 //
220 FlowPath existingFlowPath =
221 allFlowPaths.get(flowPath.flowId().value());
222 if (existingFlowPath == null)
223 continue; // Nothing to do
224
225 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
226 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
227 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
228 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
229 }
230
231 allFlowPaths.remove(existingFlowPath.flowId());
232 modifiedFlowPaths.add(existingFlowPath);
233
234 break;
235 }
236 }
237 }
238
239 //
240 // Process the topology events
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700241 //
242 boolean isTopologyModified = false;
243 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
244 TopologyElement topologyElement = eventEntry.eventData();
245 switch (eventEntry.eventType()) {
246 case ENTRY_ADD:
247 isTopologyModified = topology.addTopologyElement(topologyElement);
248 break;
249 case ENTRY_REMOVE:
250 isTopologyModified = topology.removeTopologyElement(topologyElement);
251 break;
252 }
253 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700254 if (isTopologyModified) {
255 // TODO: For now, if the topology changes, we recompute all Flows
256 recomputeFlowPaths.addAll(allFlowPaths.values());
257 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700258
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700259 // Add all new Flows
260 for (FlowPath flowPath : newFlowPaths) {
261 allFlowPaths.put(flowPath.flowId().value(), flowPath);
262 }
263
264 // Recompute all affected Flow Paths and keep only the modified
265 for (FlowPath flowPath : recomputeFlowPaths) {
266 if (recomputeFlowPath(flowPath))
267 modifiedFlowPaths.add(flowPath);
268 }
269
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700270 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700271 // Process previously unmatched Flow Entry updates
272 //
273 if ((! flowPathEvents.isEmpty()) && (! unmatchedFlowEntryUpdates.isEmpty())) {
274 List<FlowEntry> remainingUpdates = new LinkedList<FlowEntry>();
275 for (FlowEntry flowEntry : unmatchedFlowEntryUpdates) {
276 if (! updateFlowEntry(flowEntry))
277 remainingUpdates.add(flowEntry);
278 }
279 unmatchedFlowEntryUpdates = remainingUpdates;
280 }
281
282 //
283 // Process the Flow Entry events
284 //
285 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
286 FlowEntry flowEntry = eventEntry.eventData();
287 switch (eventEntry.eventType()) {
288 case ENTRY_ADD:
289 //
290 // Find the corresponding Flow Entry and update it.
291 // If not found, then keep it in a local cache for
292 // later matching.
293 //
294 if (! updateFlowEntry(flowEntry))
295 unmatchedFlowEntryUpdates.add(flowEntry);
296 break;
297 case ENTRY_REMOVE:
298 //
299 // NOTE: For now we remove the Flow Entries based on
300 // local decisions, so no need to remove them because of an
301 // external event.
302 //
303 break;
304 }
305 }
306
307 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700308 // Push the Flow Entries that have been modified
309 //
Pavlin Radoslavovebc8b192013-10-29 15:35:35 -0700310 flowManager.pushModifiedFlowEntries(modifiedFlowPaths);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700311
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700312 // Cleanup
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700313 topologyEvents.clear();
314 flowPathEvents.clear();
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700315 flowEntryEvents.clear();
316 }
317
318 /**
319 * Update a Flow Entry because of an external event.
320 *
321 * @param flowEntry the FlowEntry with the new state.
322 * @return true if the Flow Entry was found and updated, otherwise false.
323 */
324 private boolean updateFlowEntry(FlowEntry flowEntry) {
325 if ((! flowEntry.isValidFlowId()) ||
326 (! flowEntry.isValidFlowEntryId())) {
327 //
328 // Ignore events for Flow Entries with invalid Flow ID or
329 // Flow Entry ID.
330 // This shouldn't happen.
331 //
332 return true;
333 }
334
335 FlowPath flowPath = allFlowPaths.get(flowEntry.flowId().value());
336 if (flowPath == null)
337 return false;
338
339 //
340 // Iterate over all Flow Entries and find a match based on the DPID
341 //
342 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
343 if (localFlowEntry.dpid().value() != flowEntry.dpid().value())
344 continue;
345 //
346 // TODO: We might want to check the FlowEntryMatch and
347 // FlowEntryActions to double-check it is the same Flow Entry
348 //
349
350 //
351 // Local Flow Entry match found
352 //
353 if (localFlowEntry.isValidFlowEntryId()) {
354 if (localFlowEntry.flowEntryId().value() !=
355 flowEntry.flowEntryId().value()) {
356 //
357 // Find a local Flow Entry, but the Flow Entry ID doesn't
358 // match. Ignore the event.
359 //
360 return true;
361 }
362 } else {
363 // Update the Flow Entry ID
364 FlowEntryId flowEntryId =
365 new FlowEntryId(flowEntry.flowEntryId().value());
366 localFlowEntry.setFlowEntryId(flowEntryId);
367 }
368
369 //
370 // Update the local Flow Entry.
371 // For now we update only the Flow Entry Switch State
372 //
373 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
374 return true;
375 }
376
377 return false; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700378 }
379
380 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700381 * Recompute a Flow Path.
382 *
383 * @param flowPath the Flow Path to recompute.
384 * @return true if the recomputed Flow Path has changed, otherwise false.
385 */
386 private boolean recomputeFlowPath(FlowPath flowPath) {
387 boolean hasChanged = false;
388
389 //
390 // Test whether the Flow Path needs to be recomputed
391 //
392 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700393 case FP_TYPE_UNKNOWN:
394 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700395 case FP_TYPE_SHORTEST_PATH:
396 break;
397 case FP_TYPE_EXPLICIT_PATH:
398 return false; // An explicit path never changes
399 }
400
401 DataPath oldDataPath = flowPath.dataPath();
402
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700403 // Compute the new path
404 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
405 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700406 if (newDataPath == null) {
407 // We need the DataPath to compare the paths
408 newDataPath = new DataPath();
409 }
410 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
411
412 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700413 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700414 //
415 if (oldDataPath.flowEntries().size() !=
416 newDataPath.flowEntries().size()) {
417 hasChanged = true;
418 } else {
419 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
420 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
421 while (oldIter.hasNext() && newIter.hasNext()) {
422 FlowEntry oldFlowEntry = oldIter.next();
423 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700424 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
425 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700426 hasChanged = true;
427 break;
428 }
429 }
430 }
431 if (! hasChanged)
432 return hasChanged;
433
434 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700435 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700436 // - If a Flow Entry for a switch is in the old data path, but not
437 // in the new data path, then mark it for deletion.
438 // - If a Flow Entry for a switch is in the new data path, but not
439 // in the old data path, then mark it for addition.
440 // - If a Flow Entry for a switch is in both the old and the new
441 // data path, but it has changed, e.g., the incoming and/or outgoing
442 // port(s), then mark the old Flow Entry for deletion, and mark
443 // the new Flow Entry for addition.
444 // - If a Flow Entry for a switch is in both the old and the new
445 // data path, and it hasn't changed, then just keep it.
446 //
447 // NOTE: We use the Switch DPID of each entry to match the entries
448 //
449 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
450 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
451 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
452 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
453
454 // Prepare maps with the Flow Entries, so they are fast to lookup
455 for (FlowEntry flowEntry : oldDataPath.flowEntries())
456 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
457 for (FlowEntry flowEntry : newDataPath.flowEntries())
458 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
459
460 //
461 // Find the old Flow Entries that should be deleted
462 //
463 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
464 FlowEntry newFlowEntry =
465 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
466 if (newFlowEntry == null) {
467 // The old Flow Entry should be deleted
468 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
469 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
470 deletedFlowEntries.add(oldFlowEntry);
471 }
472 }
473
474 //
475 // Find the new Flow Entries that should be added or updated
476 //
477 int idx = 0;
478 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
479 FlowEntry oldFlowEntry =
480 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
481
482 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700483 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
484 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700485 //
486 // Both Flow Entries are same
487 //
488 finalFlowEntries.add(oldFlowEntry);
489 idx++;
490 continue;
491 }
492
493 if (oldFlowEntry != null) {
494 //
495 // The old Flow Entry should be deleted
496 //
497 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
498 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
499 deletedFlowEntries.add(oldFlowEntry);
500 }
501
502 //
503 // Add the new Flow Entry
504 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700505 //
506 // NOTE: Assign only the Flow ID.
507 // The Flow Entry ID is assigned later only for the Flow Entries
508 // this instance is responsible for.
509 //
510 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700511
512 // Set the incoming port matching
513 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
514 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
515 flowEntryMatch.enableInPort(newFlowEntry.inPort());
516
517 //
518 // Set the actions:
519 // If the first Flow Entry, copy the Flow Path actions to it.
520 //
521 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
522 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
523 FlowEntryActions flowActions =
524 new FlowEntryActions(flowPath.flowEntryActions());
525 for (FlowEntryAction action : flowActions.actions())
526 flowEntryActions.addAction(action);
527 }
528 idx++;
529
530 //
531 // Add the outgoing port output action
532 //
533 FlowEntryAction flowEntryAction = new FlowEntryAction();
534 flowEntryAction.setActionOutput(newFlowEntry.outPort());
535 flowEntryActions.addAction(flowEntryAction);
536
537 //
538 // Set the state of the new Flow Entry
539 //
540 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
541 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
542 finalFlowEntries.add(newFlowEntry);
543 }
544
545 //
546 // Replace the old Flow Entries with the new Flow Entries.
547 // Note that the Flow Entries that will be deleted are added at
548 // the end.
549 //
550 for (FlowEntry flowEntry : deletedFlowEntries)
551 finalFlowEntries.add(flowEntry);
552 flowPath.dataPath().setFlowEntries(finalFlowEntries);
553
554 return hasChanged;
555 }
556
557 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700558 * Receive a notification that a Flow is added.
559 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700560 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700561 */
562 @Override
563 public void notificationRecvFlowAdded(FlowPath flowPath) {
564 EventEntry<FlowPath> eventEntry =
565 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
566 networkEvents.add(eventEntry);
567 }
568
569 /**
570 * Receive a notification that a Flow is removed.
571 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700572 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700573 */
574 @Override
575 public void notificationRecvFlowRemoved(FlowPath flowPath) {
576 EventEntry<FlowPath> eventEntry =
577 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
578 networkEvents.add(eventEntry);
579 }
580
581 /**
582 * Receive a notification that a Flow is updated.
583 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700584 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700585 */
586 @Override
587 public void notificationRecvFlowUpdated(FlowPath flowPath) {
588 // NOTE: The ADD and UPDATE events are processed in same way
589 EventEntry<FlowPath> eventEntry =
590 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
591 networkEvents.add(eventEntry);
592 }
593
594 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700595 * Receive a notification that a FlowEntry is added.
596 *
597 * @param flowEntry the FlowEntry that is added.
598 */
599 @Override
600 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
601 EventEntry<FlowEntry> eventEntry =
602 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
603 networkEvents.add(eventEntry);
604 }
605
606 /**
607 * Receive a notification that a FlowEntry is removed.
608 *
609 * @param flowEntry the FlowEntry that is removed.
610 */
611 @Override
612 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
613 EventEntry<FlowEntry> eventEntry =
614 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
615 networkEvents.add(eventEntry);
616 }
617
618 /**
619 * Receive a notification that a FlowEntry is updated.
620 *
621 * @param flowEntry the FlowEntry that is updated.
622 */
623 @Override
624 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
625 // NOTE: The ADD and UPDATE events are processed in same way
626 EventEntry<FlowEntry> eventEntry =
627 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
628 networkEvents.add(eventEntry);
629 }
630
631 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700632 * Receive a notification that a Topology Element is added.
633 *
634 * @param topologyElement the Topology Element that is added.
635 */
636 @Override
637 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
638 EventEntry<TopologyElement> eventEntry =
639 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
640 networkEvents.add(eventEntry);
641 }
642
643 /**
644 * Receive a notification that a Topology Element is removed.
645 *
646 * @param topologyElement the Topology Element that is removed.
647 */
648 @Override
649 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
650 EventEntry<TopologyElement> eventEntry =
651 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
652 networkEvents.add(eventEntry);
653 }
654
655 /**
656 * Receive a notification that a Topology Element is updated.
657 *
658 * @param topologyElement the Topology Element that is updated.
659 */
660 @Override
661 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
662 // NOTE: The ADD and UPDATE events are processed in same way
663 EventEntry<TopologyElement> eventEntry =
664 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
665 networkEvents.add(eventEntry);
666 }
667}