blob: 0e9887a438368ace38a0a39c813f009e89f7860b [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/**
Pavlin Radoslavov63117172013-11-07 02:18:37 -080035 * A class for storing a pair of Flow Path and a Flow Entry.
36 */
37class FlowPathEntryPair {
38 protected FlowPath flowPath;
39 protected FlowEntry flowEntry;
40
41 protected FlowPathEntryPair(FlowPath flowPath, FlowEntry flowEntry) {
42 this.flowPath = flowPath;
43 this.flowEntry = flowEntry;
44 }
45}
46
47/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070048 * Class for FlowPath Maintenance.
49 * This class listens for FlowEvents to:
50 * - Maintain a local cache of the Network Topology.
51 * - Detect FlowPaths impacted by Topology change.
52 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070053 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070054class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070055 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070056 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070057
58 private FlowManager flowManager; // The Flow Manager to use
59 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070060 private Topology topology; // The network topology
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070061 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
Pavlin Radoslavov63117172013-11-07 02:18:37 -080062 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
63 new HashMap<Long, FlowEntry>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070064
65 // The queue with Flow Path and Topology Element updates
66 private BlockingQueue<EventEntry<?>> networkEvents =
67 new LinkedBlockingQueue<EventEntry<?>>();
68
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070069 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070070 private List<EventEntry<TopologyElement>> topologyEvents =
71 new LinkedList<EventEntry<TopologyElement>>();
72 private List<EventEntry<FlowPath>> flowPathEvents =
73 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070074 private List<EventEntry<FlowEntry>> flowEntryEvents =
75 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070076
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080077 //
78 // Transient state for processing the Flow Paths:
79 // - The new Flow Paths
80 // - The Flow Paths that should be recomputed
81 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov63117172013-11-07 02:18:37 -080082 // - The Flow Entries that were updated
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080083 //
84 private List<FlowPath> newFlowPaths = new LinkedList<FlowPath>();
85 private List<FlowPath> recomputeFlowPaths = new LinkedList<FlowPath>();
86 private List<FlowPath> modifiedFlowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavov63117172013-11-07 02:18:37 -080087 private List<FlowPathEntryPair> updatedFlowEntries =
88 new LinkedList<FlowPathEntryPair>();
89 private List<FlowPathEntryPair> unmatchedDeleteFlowEntries =
90 new LinkedList<FlowPathEntryPair>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080091
92
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070093 /**
94 * Constructor for a given Flow Manager and Datagrid Service.
95 *
96 * @param flowManager the Flow Manager to use.
97 * @param datagridService the Datagrid Service to use.
98 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070099 FlowEventHandler(FlowManager flowManager,
100 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700101 this.flowManager = flowManager;
102 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700103 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700104 }
105
106 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800107 * Get the network topology.
108 *
109 * @return the network topology.
110 */
111 protected Topology getTopology() { return this.topology; }
112
113 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800114 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700115 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800116 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700117 //
118 // Obtain the initial Topology state
119 //
120 Collection<TopologyElement> topologyElements =
121 datagridService.getAllTopologyElements();
122 for (TopologyElement topologyElement : topologyElements) {
123 EventEntry<TopologyElement> eventEntry =
124 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
125 topologyEvents.add(eventEntry);
126 }
127 //
128 // Obtain the initial Flow Path state
129 //
130 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
131 for (FlowPath flowPath : flowPaths) {
132 EventEntry<FlowPath> eventEntry =
133 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
134 flowPathEvents.add(eventEntry);
135 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700136 //
137 // Obtain the initial FlowEntry state
138 //
139 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
140 for (FlowEntry flowEntry : flowEntries) {
141 EventEntry<FlowEntry> eventEntry =
142 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
143 flowEntryEvents.add(eventEntry);
144 }
145
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800146 // Process the initial events (if any)
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700147 processEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800148 }
149
150 /**
151 * Run the thread.
152 */
153 @Override
154 public void run() {
155 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700156
157 //
158 // The main loop
159 //
160 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
161 try {
162 while (true) {
163 EventEntry<?> eventEntry = networkEvents.take();
164 collection.add(eventEntry);
165 networkEvents.drainTo(collection);
166
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700167 //
168 // Demultiplex all events:
169 // - EventEntry<TopologyElement>
170 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700171 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700172 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700173 for (EventEntry<?> event : collection) {
174 if (event.eventData() instanceof TopologyElement) {
175 EventEntry<TopologyElement> topologyEventEntry =
176 (EventEntry<TopologyElement>)event;
177 topologyEvents.add(topologyEventEntry);
178 } else if (event.eventData() instanceof FlowPath) {
179 EventEntry<FlowPath> flowPathEventEntry =
180 (EventEntry<FlowPath>)event;
181 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700182 } else if (event.eventData() instanceof FlowEntry) {
183 EventEntry<FlowEntry> flowEntryEventEntry =
184 (EventEntry<FlowEntry>)event;
185 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700186 }
187 }
188 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700189
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700190 // Process the events (if any)
191 processEvents();
192 }
193 } catch (Exception exception) {
194 log.debug("Exception processing Network Events: ", exception);
195 }
196 }
197
198 /**
199 * Process the events (if any)
200 */
201 private void processEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800202 List<FlowPathEntryPair> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700203
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700204 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
205 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700206 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700207 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700208
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800209 processFlowPathEvents();
210 processTopologyEvents();
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700211 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800212 // Add all new Flows: should be done after processing the Flow Path
213 // and Topology events.
214 //
215 for (FlowPath flowPath : newFlowPaths) {
216 allFlowPaths.put(flowPath.flowId().value(), flowPath);
217 }
218
219 processFlowEntryEvents();
220
221 // Recompute all affected Flow Paths and keep only the modified
222 for (FlowPath flowPath : recomputeFlowPaths) {
223 if (recomputeFlowPath(flowPath))
224 modifiedFlowPaths.add(flowPath);
225 }
226
227 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths);
228
229 // Assign missing Flow Entry IDs
230 assignFlowEntryId(modifiedFlowEntries);
231
232 //
233 // Push the modified Flow Entries to switches, datagrid and database
234 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800235 flowManager.pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800236 flowManager.pushModifiedFlowEntriesToDatagrid(modifiedFlowEntries);
237 flowManager.pushModifiedFlowEntriesToDatabase(modifiedFlowEntries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800238 flowManager.pushModifiedFlowEntriesToDatabase(updatedFlowEntries);
239 flowManager.pushModifiedFlowEntriesToDatabase(unmatchedDeleteFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800240
241 //
242 // Remove Flow Entries that were deleted
243 //
244 for (FlowPath flowPath : modifiedFlowPaths)
245 flowPath.dataPath().removeDeletedFlowEntries();
246
247 // Cleanup
248 topologyEvents.clear();
249 flowPathEvents.clear();
250 flowEntryEvents.clear();
251 //
252 newFlowPaths.clear();
253 recomputeFlowPaths.clear();
254 modifiedFlowPaths.clear();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800255 updatedFlowEntries.clear();
256 unmatchedDeleteFlowEntries.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800257 }
258
259 /**
260 * Extract the modified Flow Entries.
261 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800262 private List<FlowPathEntryPair> extractModifiedFlowEntries(
263 List<FlowPath> modifiedFlowPaths) {
264 List<FlowPathEntryPair> modifiedFlowEntries =
265 new LinkedList<FlowPathEntryPair>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800266
267 // Extract only the modified Flow Entries
268 for (FlowPath flowPath : modifiedFlowPaths) {
269 for (FlowEntry flowEntry : flowPath.flowEntries()) {
270 if (flowEntry.flowEntrySwitchState() ==
271 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800272 FlowPathEntryPair flowPair =
273 new FlowPathEntryPair(flowPath, flowEntry);
274 modifiedFlowEntries.add(flowPair);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800275 }
276 }
277 }
278 return modifiedFlowEntries;
279 }
280
281 /**
282 * Assign the Flow Entry ID as needed.
283 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800284 private void assignFlowEntryId(List<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800285 if (modifiedFlowEntries.isEmpty())
286 return;
287
288 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
289
290 //
291 // Assign the Flow Entry ID only for Flow Entries for my switches
292 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800293 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
294 FlowEntry flowEntry = flowPair.flowEntry;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800295 // Update the Flow Entries only for my switches
296 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
297 if (mySwitch == null)
298 continue;
299 if (! flowEntry.isValidFlowEntryId()) {
300 long id = flowManager.getNextFlowEntryId();
301 flowEntry.setFlowEntryId(new FlowEntryId(id));
302 }
303 }
304 }
305
306 /**
307 * Process the Flow Path events.
308 */
309 private void processFlowPathEvents() {
310 //
311 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700312 //
313 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
314 FlowPath flowPath = eventEntry.eventData();
315
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800316 log.debug("Flow Event: {} {}", eventEntry.eventType(),
317 flowPath.toString());
318
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700319 switch (eventEntry.eventType()) {
320 case ENTRY_ADD: {
321 //
322 // Add a new Flow Path
323 //
324 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
325 //
326 // TODO: What to do if the Flow Path already exists?
327 // Remove and then re-add it, or merge the info?
328 // For now, we don't have to do anything.
329 //
330 break;
331 }
332
333 switch (flowPath.flowPathType()) {
334 case FP_TYPE_SHORTEST_PATH:
335 //
336 // Reset the Data Path, in case it was set already, because
337 // we are going to recompute it anyway.
338 //
339 flowPath.flowEntries().clear();
340 recomputeFlowPaths.add(flowPath);
341 break;
342 case FP_TYPE_EXPLICIT_PATH:
343 //
344 // Mark all Flow Entries for installation in the switches.
345 //
346 for (FlowEntry flowEntry : flowPath.flowEntries()) {
347 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
348 }
349 modifiedFlowPaths.add(flowPath);
350 break;
351 }
352 newFlowPaths.add(flowPath);
353
354 break;
355 }
356
357 case ENTRY_REMOVE: {
358 //
359 // Remove an existing Flow Path.
360 //
361 // Find the Flow Path, and mark the Flow and its Flow Entries
362 // for deletion.
363 //
364 FlowPath existingFlowPath =
365 allFlowPaths.get(flowPath.flowId().value());
366 if (existingFlowPath == null)
367 continue; // Nothing to do
368
369 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
370 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
371 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
372 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
373 }
374
Yuta HIGUCHI2b5d0712013-10-30 15:48:13 -0700375 allFlowPaths.remove(existingFlowPath.flowId().value());
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700376 modifiedFlowPaths.add(existingFlowPath);
377
378 break;
379 }
380 }
381 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800382 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700383
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800384 /**
385 * Process the Topology events.
386 */
387 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700388 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800389 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700390 //
391 boolean isTopologyModified = false;
392 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
393 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800394
395 log.debug("Topology Event: {} {}", eventEntry.eventType(),
396 topologyElement.toString());
397
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700398 switch (eventEntry.eventType()) {
399 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700400 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700401 break;
402 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700403 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700404 break;
405 }
406 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700407 if (isTopologyModified) {
408 // TODO: For now, if the topology changes, we recompute all Flows
409 recomputeFlowPaths.addAll(allFlowPaths.values());
410 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800411 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700412
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800413 /**
414 * Process the Flow Entry events.
415 */
416 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800417 FlowPathEntryPair flowPair;
418 FlowPath flowPath;
419 FlowEntry updatedFlowEntry;
420
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700421 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800422 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700423 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800424 if (! unmatchedFlowEntryAdd.isEmpty()) {
425 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
426 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
427 flowPath = allFlowPaths.get(flowEntry.flowId().value());
428 if (flowPath == null)
429 continue;
430 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
431 if (updatedFlowEntry == null) {
432 remainingUpdates.put(flowEntry.flowEntryId().value(),
433 flowEntry);
434 continue;
435 }
436 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
437 updatedFlowEntries.add(flowPair);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700438 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800439 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700440 }
441
442 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800443 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700444 //
445 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
446 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800447
448 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
449 flowEntry.toString());
450
451 if ((! flowEntry.isValidFlowId()) ||
452 (! flowEntry.isValidFlowEntryId())) {
453 continue;
454 }
455
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700456 switch (eventEntry.eventType()) {
457 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800458 flowPath = allFlowPaths.get(flowEntry.flowId().value());
459 if (flowPath == null) {
460 // Flow Path not found: keep the entry for later matching
461 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
462 flowEntry);
463 break;
464 }
465 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
466 if (updatedFlowEntry == null) {
467 // Flow Entry not found: keep the entry for later matching
468 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
469 flowEntry);
470 break;
471 }
472 // Add the updated entry to the list of updated Flow Entries
473 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
474 updatedFlowEntries.add(flowPair);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700475 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800476
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700477 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800478 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
479 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
480 continue; // Match found
481 }
482
483 flowPath = allFlowPaths.get(flowEntry.flowId().value());
484 if (flowPath == null) {
485 // Flow Path not found: ignore the update
486 break;
487 }
488 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
489 if (updatedFlowEntry == null) {
490 // Flow Entry not found: add to list of deleted entries
491 flowPair = new FlowPathEntryPair(flowPath, flowEntry);
492 unmatchedDeleteFlowEntries.add(flowPair);
493 break;
494 }
495 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
496 updatedFlowEntries.add(flowPair);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700497 break;
498 }
499 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700500 }
501
502 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800503 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700504 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800505 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700506 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700508 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800509 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
510 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700511 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800512 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700513 //
514 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800515 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
516 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700517 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800518 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700519
520 //
521 // Local Flow Entry match found
522 //
523 if (localFlowEntry.isValidFlowEntryId()) {
524 if (localFlowEntry.flowEntryId().value() !=
525 flowEntry.flowEntryId().value()) {
526 //
527 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800528 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700529 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800530 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700531 }
532 } else {
533 // Update the Flow Entry ID
534 FlowEntryId flowEntryId =
535 new FlowEntryId(flowEntry.flowEntryId().value());
536 localFlowEntry.setFlowEntryId(flowEntryId);
537 }
538
539 //
540 // Update the local Flow Entry.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700541 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800542 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700543 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800544 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700545 }
546
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800547 return null; // Entry not found
548 }
549
550 /**
551 * Update a Flow Entry because of an external ENTRY_REMOVE event.
552 *
553 * @param flowPath the FlowPath for the Flow Entry to update.
554 * @param flowEntry the FlowEntry with the new state.
555 * @return the updated Flow Entry if found, otherwise null.
556 */
557 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
558 FlowEntry flowEntry) {
559 //
560 // Iterate over all Flow Entries and find a match based on
561 // the Flow Entry ID.
562 //
563 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
564 if (! localFlowEntry.isValidFlowEntryId())
565 continue;
566 if (localFlowEntry.flowEntryId().value() !=
567 flowEntry.flowEntryId().value()) {
568 continue;
569 }
570 //
571 // Update the local Flow Entry.
572 //
573 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
574 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
575 return localFlowEntry;
576 }
577
578 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700579 }
580
581 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700582 * Recompute a Flow Path.
583 *
584 * @param flowPath the Flow Path to recompute.
585 * @return true if the recomputed Flow Path has changed, otherwise false.
586 */
587 private boolean recomputeFlowPath(FlowPath flowPath) {
588 boolean hasChanged = false;
589
590 //
591 // Test whether the Flow Path needs to be recomputed
592 //
593 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700594 case FP_TYPE_UNKNOWN:
595 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700596 case FP_TYPE_SHORTEST_PATH:
597 break;
598 case FP_TYPE_EXPLICIT_PATH:
599 return false; // An explicit path never changes
600 }
601
602 DataPath oldDataPath = flowPath.dataPath();
603
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700604 // Compute the new path
605 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
606 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700607 if (newDataPath == null) {
608 // We need the DataPath to compare the paths
609 newDataPath = new DataPath();
610 }
611 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
612
613 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700614 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700615 //
616 if (oldDataPath.flowEntries().size() !=
617 newDataPath.flowEntries().size()) {
618 hasChanged = true;
619 } else {
620 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
621 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
622 while (oldIter.hasNext() && newIter.hasNext()) {
623 FlowEntry oldFlowEntry = oldIter.next();
624 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700625 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
626 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700627 hasChanged = true;
628 break;
629 }
630 }
631 }
632 if (! hasChanged)
633 return hasChanged;
634
635 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700636 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700637 // - If a Flow Entry for a switch is in the old data path, but not
638 // in the new data path, then mark it for deletion.
639 // - If a Flow Entry for a switch is in the new data path, but not
640 // in the old data path, then mark it for addition.
641 // - If a Flow Entry for a switch is in both the old and the new
642 // data path, but it has changed, e.g., the incoming and/or outgoing
643 // port(s), then mark the old Flow Entry for deletion, and mark
644 // the new Flow Entry for addition.
645 // - If a Flow Entry for a switch is in both the old and the new
646 // data path, and it hasn't changed, then just keep it.
647 //
648 // NOTE: We use the Switch DPID of each entry to match the entries
649 //
650 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
651 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
652 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
653 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
654
655 // Prepare maps with the Flow Entries, so they are fast to lookup
656 for (FlowEntry flowEntry : oldDataPath.flowEntries())
657 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
658 for (FlowEntry flowEntry : newDataPath.flowEntries())
659 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
660
661 //
662 // Find the old Flow Entries that should be deleted
663 //
664 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
665 FlowEntry newFlowEntry =
666 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
667 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800668 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700669 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
670 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
671 deletedFlowEntries.add(oldFlowEntry);
672 }
673 }
674
675 //
676 // Find the new Flow Entries that should be added or updated
677 //
678 int idx = 0;
679 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
680 FlowEntry oldFlowEntry =
681 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
682
683 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700684 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
685 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700686 //
687 // Both Flow Entries are same
688 //
689 finalFlowEntries.add(oldFlowEntry);
690 idx++;
691 continue;
692 }
693
694 if (oldFlowEntry != null) {
695 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800696 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700697 //
698 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
699 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
700 deletedFlowEntries.add(oldFlowEntry);
701 }
702
703 //
704 // Add the new Flow Entry
705 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700706 //
707 // NOTE: Assign only the Flow ID.
708 // The Flow Entry ID is assigned later only for the Flow Entries
709 // this instance is responsible for.
710 //
711 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700712
713 // Set the incoming port matching
714 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
715 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
716 flowEntryMatch.enableInPort(newFlowEntry.inPort());
717
718 //
719 // Set the actions:
720 // If the first Flow Entry, copy the Flow Path actions to it.
721 //
722 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
723 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
724 FlowEntryActions flowActions =
725 new FlowEntryActions(flowPath.flowEntryActions());
726 for (FlowEntryAction action : flowActions.actions())
727 flowEntryActions.addAction(action);
728 }
729 idx++;
730
731 //
732 // Add the outgoing port output action
733 //
734 FlowEntryAction flowEntryAction = new FlowEntryAction();
735 flowEntryAction.setActionOutput(newFlowEntry.outPort());
736 flowEntryActions.addAction(flowEntryAction);
737
738 //
739 // Set the state of the new Flow Entry
740 //
741 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
742 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
743 finalFlowEntries.add(newFlowEntry);
744 }
745
746 //
747 // Replace the old Flow Entries with the new Flow Entries.
748 // Note that the Flow Entries that will be deleted are added at
749 // the end.
750 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800751 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700752 flowPath.dataPath().setFlowEntries(finalFlowEntries);
753
754 return hasChanged;
755 }
756
757 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700758 * Receive a notification that a Flow is added.
759 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700760 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700761 */
762 @Override
763 public void notificationRecvFlowAdded(FlowPath flowPath) {
764 EventEntry<FlowPath> eventEntry =
765 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
766 networkEvents.add(eventEntry);
767 }
768
769 /**
770 * Receive a notification that a Flow is removed.
771 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700772 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700773 */
774 @Override
775 public void notificationRecvFlowRemoved(FlowPath flowPath) {
776 EventEntry<FlowPath> eventEntry =
777 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
778 networkEvents.add(eventEntry);
779 }
780
781 /**
782 * Receive a notification that a Flow is updated.
783 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700784 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700785 */
786 @Override
787 public void notificationRecvFlowUpdated(FlowPath flowPath) {
788 // NOTE: The ADD and UPDATE events are processed in same way
789 EventEntry<FlowPath> eventEntry =
790 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
791 networkEvents.add(eventEntry);
792 }
793
794 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700795 * Receive a notification that a FlowEntry is added.
796 *
797 * @param flowEntry the FlowEntry that is added.
798 */
799 @Override
800 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
801 EventEntry<FlowEntry> eventEntry =
802 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
803 networkEvents.add(eventEntry);
804 }
805
806 /**
807 * Receive a notification that a FlowEntry is removed.
808 *
809 * @param flowEntry the FlowEntry that is removed.
810 */
811 @Override
812 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
813 EventEntry<FlowEntry> eventEntry =
814 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
815 networkEvents.add(eventEntry);
816 }
817
818 /**
819 * Receive a notification that a FlowEntry is updated.
820 *
821 * @param flowEntry the FlowEntry that is updated.
822 */
823 @Override
824 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
825 // NOTE: The ADD and UPDATE events are processed in same way
826 EventEntry<FlowEntry> eventEntry =
827 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
828 networkEvents.add(eventEntry);
829 }
830
831 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700832 * Receive a notification that a Topology Element is added.
833 *
834 * @param topologyElement the Topology Element that is added.
835 */
836 @Override
837 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
838 EventEntry<TopologyElement> eventEntry =
839 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
840 networkEvents.add(eventEntry);
841 }
842
843 /**
844 * Receive a notification that a Topology Element is removed.
845 *
846 * @param topologyElement the Topology Element that is removed.
847 */
848 @Override
849 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
850 EventEntry<TopologyElement> eventEntry =
851 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
852 networkEvents.add(eventEntry);
853 }
854
855 /**
856 * Receive a notification that a Topology Element is updated.
857 *
858 * @param topologyElement the Topology Element that is updated.
859 */
860 @Override
861 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
862 // NOTE: The ADD and UPDATE events are processed in same way
863 EventEntry<TopologyElement> eventEntry =
864 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
865 networkEvents.add(eventEntry);
866 }
867}