blob: f3e47f4617633941ba5621b55831487868deb94b [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
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080013import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070014import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070015import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070016import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070017import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070018import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070019import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070020import net.onrc.onos.ofcontroller.util.FlowEntry;
21import net.onrc.onos.ofcontroller.util.FlowEntryAction;
22import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070023import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070024import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
25import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
26import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070027import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070028import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070029import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070030
31import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
34/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070035 * Class for FlowPath Maintenance.
36 * This class listens for FlowEvents to:
37 * - Maintain a local cache of the Network Topology.
38 * - Detect FlowPaths impacted by Topology change.
39 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070040 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070041class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070042 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070043 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070044
45 private FlowManager flowManager; // The Flow Manager to use
46 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070047 private Topology topology; // The network topology
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070048 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070049 private List<FlowEntry> unmatchedFlowEntryUpdates =
50 new LinkedList<FlowEntry>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070051
52 // The queue with Flow Path and Topology Element updates
53 private BlockingQueue<EventEntry<?>> networkEvents =
54 new LinkedBlockingQueue<EventEntry<?>>();
55
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070056 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070057 private List<EventEntry<TopologyElement>> topologyEvents =
58 new LinkedList<EventEntry<TopologyElement>>();
59 private List<EventEntry<FlowPath>> flowPathEvents =
60 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070061 private List<EventEntry<FlowEntry>> flowEntryEvents =
62 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070063
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080064 //
65 // Transient state for processing the Flow Paths:
66 // - The new Flow Paths
67 // - The Flow Paths that should be recomputed
68 // - The Flow Paths with modified Flow Entries
69 //
70 private List<FlowPath> newFlowPaths = new LinkedList<FlowPath>();
71 private List<FlowPath> recomputeFlowPaths = new LinkedList<FlowPath>();
72 private List<FlowPath> modifiedFlowPaths = new LinkedList<FlowPath>();
73
74
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070075 /**
76 * Constructor for a given Flow Manager and Datagrid Service.
77 *
78 * @param flowManager the Flow Manager to use.
79 * @param datagridService the Datagrid Service to use.
80 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070081 FlowEventHandler(FlowManager flowManager,
82 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070083 this.flowManager = flowManager;
84 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070085 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070086 }
87
88 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -080089 * Get the network topology.
90 *
91 * @return the network topology.
92 */
93 protected Topology getTopology() { return this.topology; }
94
95 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080096 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070097 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080098 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070099 //
100 // Obtain the initial Topology state
101 //
102 Collection<TopologyElement> topologyElements =
103 datagridService.getAllTopologyElements();
104 for (TopologyElement topologyElement : topologyElements) {
105 EventEntry<TopologyElement> eventEntry =
106 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
107 topologyEvents.add(eventEntry);
108 }
109 //
110 // Obtain the initial Flow Path state
111 //
112 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
113 for (FlowPath flowPath : flowPaths) {
114 EventEntry<FlowPath> eventEntry =
115 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
116 flowPathEvents.add(eventEntry);
117 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700118 //
119 // Obtain the initial FlowEntry state
120 //
121 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
122 for (FlowEntry flowEntry : flowEntries) {
123 EventEntry<FlowEntry> eventEntry =
124 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
125 flowEntryEvents.add(eventEntry);
126 }
127
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800128 // Process the initial events (if any)
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700129 processEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800130 }
131
132 /**
133 * Run the thread.
134 */
135 @Override
136 public void run() {
137 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700138
139 //
140 // The main loop
141 //
142 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
143 try {
144 while (true) {
145 EventEntry<?> eventEntry = networkEvents.take();
146 collection.add(eventEntry);
147 networkEvents.drainTo(collection);
148
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700149 //
150 // Demultiplex all events:
151 // - EventEntry<TopologyElement>
152 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700153 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700154 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700155 for (EventEntry<?> event : collection) {
156 if (event.eventData() instanceof TopologyElement) {
157 EventEntry<TopologyElement> topologyEventEntry =
158 (EventEntry<TopologyElement>)event;
159 topologyEvents.add(topologyEventEntry);
160 } else if (event.eventData() instanceof FlowPath) {
161 EventEntry<FlowPath> flowPathEventEntry =
162 (EventEntry<FlowPath>)event;
163 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700164 } else if (event.eventData() instanceof FlowEntry) {
165 EventEntry<FlowEntry> flowEntryEventEntry =
166 (EventEntry<FlowEntry>)event;
167 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700168 }
169 }
170 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700171
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700172 // Process the events (if any)
173 processEvents();
174 }
175 } catch (Exception exception) {
176 log.debug("Exception processing Network Events: ", exception);
177 }
178 }
179
180 /**
181 * Process the events (if any)
182 */
183 private void processEvents() {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800184 List<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700185
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700186 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
187 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700188 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700189 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700190
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800191 processFlowPathEvents();
192 processTopologyEvents();
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700193 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800194 // Add all new Flows: should be done after processing the Flow Path
195 // and Topology events.
196 //
197 for (FlowPath flowPath : newFlowPaths) {
198 allFlowPaths.put(flowPath.flowId().value(), flowPath);
199 }
200
201 processFlowEntryEvents();
202
203 // Recompute all affected Flow Paths and keep only the modified
204 for (FlowPath flowPath : recomputeFlowPaths) {
205 if (recomputeFlowPath(flowPath))
206 modifiedFlowPaths.add(flowPath);
207 }
208
209 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths);
210
211 // Assign missing Flow Entry IDs
212 assignFlowEntryId(modifiedFlowEntries);
213
214 //
215 // Push the modified Flow Entries to switches, datagrid and database
216 //
217 flowManager.pushModifiedFlowEntriesToSwitches(modifiedFlowPaths);
218 flowManager.pushModifiedFlowEntriesToDatagrid(modifiedFlowEntries);
219 flowManager.pushModifiedFlowEntriesToDatabase(modifiedFlowEntries);
220
221 //
222 // Remove Flow Entries that were deleted
223 //
224 for (FlowPath flowPath : modifiedFlowPaths)
225 flowPath.dataPath().removeDeletedFlowEntries();
226
227 // Cleanup
228 topologyEvents.clear();
229 flowPathEvents.clear();
230 flowEntryEvents.clear();
231 //
232 newFlowPaths.clear();
233 recomputeFlowPaths.clear();
234 modifiedFlowPaths.clear();
235 }
236
237 /**
238 * Extract the modified Flow Entries.
239 */
240 private List<FlowEntry> extractModifiedFlowEntries(
241 List<FlowPath> modifiedFlowPaths) {
242 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
243
244 // Extract only the modified Flow Entries
245 for (FlowPath flowPath : modifiedFlowPaths) {
246 for (FlowEntry flowEntry : flowPath.flowEntries()) {
247 if (flowEntry.flowEntrySwitchState() ==
248 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
249 modifiedFlowEntries.add(flowEntry);
250 }
251 }
252 }
253 return modifiedFlowEntries;
254 }
255
256 /**
257 * Assign the Flow Entry ID as needed.
258 */
259 private void assignFlowEntryId(List<FlowEntry> modifiedFlowEntries) {
260 if (modifiedFlowEntries.isEmpty())
261 return;
262
263 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
264
265 //
266 // Assign the Flow Entry ID only for Flow Entries for my switches
267 //
268 for (FlowEntry flowEntry : modifiedFlowEntries) {
269 // Update the Flow Entries only for my switches
270 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
271 if (mySwitch == null)
272 continue;
273 if (! flowEntry.isValidFlowEntryId()) {
274 long id = flowManager.getNextFlowEntryId();
275 flowEntry.setFlowEntryId(new FlowEntryId(id));
276 }
277 }
278 }
279
280 /**
281 * Process the Flow Path events.
282 */
283 private void processFlowPathEvents() {
284 //
285 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700286 //
287 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
288 FlowPath flowPath = eventEntry.eventData();
289
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800290 log.debug("Flow Event: {} {}", eventEntry.eventType(),
291 flowPath.toString());
292
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700293 switch (eventEntry.eventType()) {
294 case ENTRY_ADD: {
295 //
296 // Add a new Flow Path
297 //
298 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
299 //
300 // TODO: What to do if the Flow Path already exists?
301 // Remove and then re-add it, or merge the info?
302 // For now, we don't have to do anything.
303 //
304 break;
305 }
306
307 switch (flowPath.flowPathType()) {
308 case FP_TYPE_SHORTEST_PATH:
309 //
310 // Reset the Data Path, in case it was set already, because
311 // we are going to recompute it anyway.
312 //
313 flowPath.flowEntries().clear();
314 recomputeFlowPaths.add(flowPath);
315 break;
316 case FP_TYPE_EXPLICIT_PATH:
317 //
318 // Mark all Flow Entries for installation in the switches.
319 //
320 for (FlowEntry flowEntry : flowPath.flowEntries()) {
321 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
322 }
323 modifiedFlowPaths.add(flowPath);
324 break;
325 }
326 newFlowPaths.add(flowPath);
327
328 break;
329 }
330
331 case ENTRY_REMOVE: {
332 //
333 // Remove an existing Flow Path.
334 //
335 // Find the Flow Path, and mark the Flow and its Flow Entries
336 // for deletion.
337 //
338 FlowPath existingFlowPath =
339 allFlowPaths.get(flowPath.flowId().value());
340 if (existingFlowPath == null)
341 continue; // Nothing to do
342
343 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
344 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
345 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
346 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
347 }
348
Yuta HIGUCHI2b5d0712013-10-30 15:48:13 -0700349 allFlowPaths.remove(existingFlowPath.flowId().value());
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700350 modifiedFlowPaths.add(existingFlowPath);
351
352 break;
353 }
354 }
355 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800356 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700357
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800358 /**
359 * Process the Topology events.
360 */
361 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700362 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800363 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700364 //
365 boolean isTopologyModified = false;
366 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
367 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800368
369 log.debug("Topology Event: {} {}", eventEntry.eventType(),
370 topologyElement.toString());
371
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700372 switch (eventEntry.eventType()) {
373 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700374 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700375 break;
376 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700377 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700378 break;
379 }
380 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700381 if (isTopologyModified) {
382 // TODO: For now, if the topology changes, we recompute all Flows
383 recomputeFlowPaths.addAll(allFlowPaths.values());
384 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800385 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700386
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800387 /**
388 * Process the Flow Entry events.
389 */
390 private void processFlowEntryEvents() {
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700391 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800392 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700393 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800394 if ((! flowPathEvents.isEmpty()) &&
395 (! unmatchedFlowEntryUpdates.isEmpty())) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700396 List<FlowEntry> remainingUpdates = new LinkedList<FlowEntry>();
397 for (FlowEntry flowEntry : unmatchedFlowEntryUpdates) {
398 if (! updateFlowEntry(flowEntry))
399 remainingUpdates.add(flowEntry);
400 }
401 unmatchedFlowEntryUpdates = remainingUpdates;
402 }
403
404 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800405 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700406 //
407 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
408 FlowEntry flowEntry = eventEntry.eventData();
409 switch (eventEntry.eventType()) {
410 case ENTRY_ADD:
411 //
412 // Find the corresponding Flow Entry and update it.
413 // If not found, then keep it in a local cache for
414 // later matching.
415 //
416 if (! updateFlowEntry(flowEntry))
417 unmatchedFlowEntryUpdates.add(flowEntry);
418 break;
419 case ENTRY_REMOVE:
420 //
421 // NOTE: For now we remove the Flow Entries based on
422 // local decisions, so no need to remove them because of an
423 // external event.
424 //
425 break;
426 }
427 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700428 }
429
430 /**
431 * Update a Flow Entry because of an external event.
432 *
433 * @param flowEntry the FlowEntry with the new state.
434 * @return true if the Flow Entry was found and updated, otherwise false.
435 */
436 private boolean updateFlowEntry(FlowEntry flowEntry) {
437 if ((! flowEntry.isValidFlowId()) ||
438 (! flowEntry.isValidFlowEntryId())) {
439 //
440 // Ignore events for Flow Entries with invalid Flow ID or
441 // Flow Entry ID.
442 // This shouldn't happen.
443 //
444 return true;
445 }
446
447 FlowPath flowPath = allFlowPaths.get(flowEntry.flowId().value());
448 if (flowPath == null)
449 return false;
450
451 //
452 // Iterate over all Flow Entries and find a match based on the DPID
453 //
454 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
455 if (localFlowEntry.dpid().value() != flowEntry.dpid().value())
456 continue;
457 //
458 // TODO: We might want to check the FlowEntryMatch and
459 // FlowEntryActions to double-check it is the same Flow Entry
460 //
461
462 //
463 // Local Flow Entry match found
464 //
465 if (localFlowEntry.isValidFlowEntryId()) {
466 if (localFlowEntry.flowEntryId().value() !=
467 flowEntry.flowEntryId().value()) {
468 //
469 // Find a local Flow Entry, but the Flow Entry ID doesn't
470 // match. Ignore the event.
471 //
472 return true;
473 }
474 } else {
475 // Update the Flow Entry ID
476 FlowEntryId flowEntryId =
477 new FlowEntryId(flowEntry.flowEntryId().value());
478 localFlowEntry.setFlowEntryId(flowEntryId);
479 }
480
481 //
482 // Update the local Flow Entry.
483 // For now we update only the Flow Entry Switch State
484 //
485 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
486 return true;
487 }
488
489 return false; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700490 }
491
492 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700493 * Recompute a Flow Path.
494 *
495 * @param flowPath the Flow Path to recompute.
496 * @return true if the recomputed Flow Path has changed, otherwise false.
497 */
498 private boolean recomputeFlowPath(FlowPath flowPath) {
499 boolean hasChanged = false;
500
501 //
502 // Test whether the Flow Path needs to be recomputed
503 //
504 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700505 case FP_TYPE_UNKNOWN:
506 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700507 case FP_TYPE_SHORTEST_PATH:
508 break;
509 case FP_TYPE_EXPLICIT_PATH:
510 return false; // An explicit path never changes
511 }
512
513 DataPath oldDataPath = flowPath.dataPath();
514
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700515 // Compute the new path
516 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
517 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700518 if (newDataPath == null) {
519 // We need the DataPath to compare the paths
520 newDataPath = new DataPath();
521 }
522 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
523
524 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700525 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700526 //
527 if (oldDataPath.flowEntries().size() !=
528 newDataPath.flowEntries().size()) {
529 hasChanged = true;
530 } else {
531 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
532 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
533 while (oldIter.hasNext() && newIter.hasNext()) {
534 FlowEntry oldFlowEntry = oldIter.next();
535 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700536 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
537 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700538 hasChanged = true;
539 break;
540 }
541 }
542 }
543 if (! hasChanged)
544 return hasChanged;
545
546 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700547 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700548 // - If a Flow Entry for a switch is in the old data path, but not
549 // in the new data path, then mark it for deletion.
550 // - If a Flow Entry for a switch is in the new data path, but not
551 // in the old data path, then mark it for addition.
552 // - If a Flow Entry for a switch is in both the old and the new
553 // data path, but it has changed, e.g., the incoming and/or outgoing
554 // port(s), then mark the old Flow Entry for deletion, and mark
555 // the new Flow Entry for addition.
556 // - If a Flow Entry for a switch is in both the old and the new
557 // data path, and it hasn't changed, then just keep it.
558 //
559 // NOTE: We use the Switch DPID of each entry to match the entries
560 //
561 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
562 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
563 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
564 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
565
566 // Prepare maps with the Flow Entries, so they are fast to lookup
567 for (FlowEntry flowEntry : oldDataPath.flowEntries())
568 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
569 for (FlowEntry flowEntry : newDataPath.flowEntries())
570 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
571
572 //
573 // Find the old Flow Entries that should be deleted
574 //
575 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
576 FlowEntry newFlowEntry =
577 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
578 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800579 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700580 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
581 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
582 deletedFlowEntries.add(oldFlowEntry);
583 }
584 }
585
586 //
587 // Find the new Flow Entries that should be added or updated
588 //
589 int idx = 0;
590 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
591 FlowEntry oldFlowEntry =
592 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
593
594 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700595 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
596 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700597 //
598 // Both Flow Entries are same
599 //
600 finalFlowEntries.add(oldFlowEntry);
601 idx++;
602 continue;
603 }
604
605 if (oldFlowEntry != null) {
606 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800607 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700608 //
609 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
610 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
611 deletedFlowEntries.add(oldFlowEntry);
612 }
613
614 //
615 // Add the new Flow Entry
616 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700617 //
618 // NOTE: Assign only the Flow ID.
619 // The Flow Entry ID is assigned later only for the Flow Entries
620 // this instance is responsible for.
621 //
622 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700623
624 // Set the incoming port matching
625 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
626 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
627 flowEntryMatch.enableInPort(newFlowEntry.inPort());
628
629 //
630 // Set the actions:
631 // If the first Flow Entry, copy the Flow Path actions to it.
632 //
633 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
634 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
635 FlowEntryActions flowActions =
636 new FlowEntryActions(flowPath.flowEntryActions());
637 for (FlowEntryAction action : flowActions.actions())
638 flowEntryActions.addAction(action);
639 }
640 idx++;
641
642 //
643 // Add the outgoing port output action
644 //
645 FlowEntryAction flowEntryAction = new FlowEntryAction();
646 flowEntryAction.setActionOutput(newFlowEntry.outPort());
647 flowEntryActions.addAction(flowEntryAction);
648
649 //
650 // Set the state of the new Flow Entry
651 //
652 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
653 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
654 finalFlowEntries.add(newFlowEntry);
655 }
656
657 //
658 // Replace the old Flow Entries with the new Flow Entries.
659 // Note that the Flow Entries that will be deleted are added at
660 // the end.
661 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800662 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700663 flowPath.dataPath().setFlowEntries(finalFlowEntries);
664
665 return hasChanged;
666 }
667
668 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700669 * Receive a notification that a Flow is added.
670 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700671 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700672 */
673 @Override
674 public void notificationRecvFlowAdded(FlowPath flowPath) {
675 EventEntry<FlowPath> eventEntry =
676 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
677 networkEvents.add(eventEntry);
678 }
679
680 /**
681 * Receive a notification that a Flow is removed.
682 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700683 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700684 */
685 @Override
686 public void notificationRecvFlowRemoved(FlowPath flowPath) {
687 EventEntry<FlowPath> eventEntry =
688 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
689 networkEvents.add(eventEntry);
690 }
691
692 /**
693 * Receive a notification that a Flow is updated.
694 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700695 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700696 */
697 @Override
698 public void notificationRecvFlowUpdated(FlowPath flowPath) {
699 // NOTE: The ADD and UPDATE events are processed in same way
700 EventEntry<FlowPath> eventEntry =
701 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
702 networkEvents.add(eventEntry);
703 }
704
705 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700706 * Receive a notification that a FlowEntry is added.
707 *
708 * @param flowEntry the FlowEntry that is added.
709 */
710 @Override
711 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
712 EventEntry<FlowEntry> eventEntry =
713 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
714 networkEvents.add(eventEntry);
715 }
716
717 /**
718 * Receive a notification that a FlowEntry is removed.
719 *
720 * @param flowEntry the FlowEntry that is removed.
721 */
722 @Override
723 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
724 EventEntry<FlowEntry> eventEntry =
725 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
726 networkEvents.add(eventEntry);
727 }
728
729 /**
730 * Receive a notification that a FlowEntry is updated.
731 *
732 * @param flowEntry the FlowEntry that is updated.
733 */
734 @Override
735 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
736 // NOTE: The ADD and UPDATE events are processed in same way
737 EventEntry<FlowEntry> eventEntry =
738 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
739 networkEvents.add(eventEntry);
740 }
741
742 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700743 * Receive a notification that a Topology Element is added.
744 *
745 * @param topologyElement the Topology Element that is added.
746 */
747 @Override
748 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
749 EventEntry<TopologyElement> eventEntry =
750 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
751 networkEvents.add(eventEntry);
752 }
753
754 /**
755 * Receive a notification that a Topology Element is removed.
756 *
757 * @param topologyElement the Topology Element that is removed.
758 */
759 @Override
760 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
761 EventEntry<TopologyElement> eventEntry =
762 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
763 networkEvents.add(eventEntry);
764 }
765
766 /**
767 * Receive a notification that a Topology Element is updated.
768 *
769 * @param topologyElement the Topology Element that is updated.
770 */
771 @Override
772 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
773 // NOTE: The ADD and UPDATE events are processed in same way
774 EventEntry<TopologyElement> eventEntry =
775 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
776 networkEvents.add(eventEntry);
777 }
778}