blob: 1c80ffc71945621f1fb9aa7aa8174a1de9568514 [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) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800174 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700175 if (event.eventData() instanceof TopologyElement) {
176 EventEntry<TopologyElement> topologyEventEntry =
177 (EventEntry<TopologyElement>)event;
178 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800179 continue;
180 }
181
182 // FlowPath event
183 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700184 EventEntry<FlowPath> flowPathEventEntry =
185 (EventEntry<FlowPath>)event;
186 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800187 continue;
188 }
189
190 // FlowEntry event
191 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700192 EventEntry<FlowEntry> flowEntryEventEntry =
193 (EventEntry<FlowEntry>)event;
194 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800195 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700196 }
197 }
198 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700199
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700200 // Process the events (if any)
201 processEvents();
202 }
203 } catch (Exception exception) {
204 log.debug("Exception processing Network Events: ", exception);
205 }
206 }
207
208 /**
209 * Process the events (if any)
210 */
211 private void processEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800212 List<FlowPathEntryPair> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700213
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700214 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
215 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700216 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700217 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700218
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800219 processFlowPathEvents();
220 processTopologyEvents();
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700221 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800222 // Add all new Flows: should be done after processing the Flow Path
223 // and Topology events.
224 //
225 for (FlowPath flowPath : newFlowPaths) {
226 allFlowPaths.put(flowPath.flowId().value(), flowPath);
227 }
228
229 processFlowEntryEvents();
230
231 // Recompute all affected Flow Paths and keep only the modified
232 for (FlowPath flowPath : recomputeFlowPaths) {
233 if (recomputeFlowPath(flowPath))
234 modifiedFlowPaths.add(flowPath);
235 }
236
237 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths);
238
239 // Assign missing Flow Entry IDs
240 assignFlowEntryId(modifiedFlowEntries);
241
242 //
243 // Push the modified Flow Entries to switches, datagrid and database
244 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800245 flowManager.pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800246 flowManager.pushModifiedFlowEntriesToDatagrid(modifiedFlowEntries);
247 flowManager.pushModifiedFlowEntriesToDatabase(modifiedFlowEntries);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800248 flowManager.pushModifiedFlowEntriesToDatabase(updatedFlowEntries);
249 flowManager.pushModifiedFlowEntriesToDatabase(unmatchedDeleteFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800250
251 //
252 // Remove Flow Entries that were deleted
253 //
254 for (FlowPath flowPath : modifiedFlowPaths)
255 flowPath.dataPath().removeDeletedFlowEntries();
256
257 // Cleanup
258 topologyEvents.clear();
259 flowPathEvents.clear();
260 flowEntryEvents.clear();
261 //
262 newFlowPaths.clear();
263 recomputeFlowPaths.clear();
264 modifiedFlowPaths.clear();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800265 updatedFlowEntries.clear();
266 unmatchedDeleteFlowEntries.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800267 }
268
269 /**
270 * Extract the modified Flow Entries.
271 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800272 private List<FlowPathEntryPair> extractModifiedFlowEntries(
273 List<FlowPath> modifiedFlowPaths) {
274 List<FlowPathEntryPair> modifiedFlowEntries =
275 new LinkedList<FlowPathEntryPair>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800276
277 // Extract only the modified Flow Entries
278 for (FlowPath flowPath : modifiedFlowPaths) {
279 for (FlowEntry flowEntry : flowPath.flowEntries()) {
280 if (flowEntry.flowEntrySwitchState() ==
281 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800282 FlowPathEntryPair flowPair =
283 new FlowPathEntryPair(flowPath, flowEntry);
284 modifiedFlowEntries.add(flowPair);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800285 }
286 }
287 }
288 return modifiedFlowEntries;
289 }
290
291 /**
292 * Assign the Flow Entry ID as needed.
293 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800294 private void assignFlowEntryId(List<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800295 if (modifiedFlowEntries.isEmpty())
296 return;
297
298 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
299
300 //
301 // Assign the Flow Entry ID only for Flow Entries for my switches
302 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800303 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
304 FlowEntry flowEntry = flowPair.flowEntry;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800305 // Update the Flow Entries only for my switches
306 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
307 if (mySwitch == null)
308 continue;
309 if (! flowEntry.isValidFlowEntryId()) {
310 long id = flowManager.getNextFlowEntryId();
311 flowEntry.setFlowEntryId(new FlowEntryId(id));
312 }
313 }
314 }
315
316 /**
317 * Process the Flow Path events.
318 */
319 private void processFlowPathEvents() {
320 //
321 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700322 //
323 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
324 FlowPath flowPath = eventEntry.eventData();
325
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800326 log.debug("Flow Event: {} {}", eventEntry.eventType(),
327 flowPath.toString());
328
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700329 switch (eventEntry.eventType()) {
330 case ENTRY_ADD: {
331 //
332 // Add a new Flow Path
333 //
334 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
335 //
336 // TODO: What to do if the Flow Path already exists?
337 // Remove and then re-add it, or merge the info?
338 // For now, we don't have to do anything.
339 //
340 break;
341 }
342
343 switch (flowPath.flowPathType()) {
344 case FP_TYPE_SHORTEST_PATH:
345 //
346 // Reset the Data Path, in case it was set already, because
347 // we are going to recompute it anyway.
348 //
349 flowPath.flowEntries().clear();
350 recomputeFlowPaths.add(flowPath);
351 break;
352 case FP_TYPE_EXPLICIT_PATH:
353 //
354 // Mark all Flow Entries for installation in the switches.
355 //
356 for (FlowEntry flowEntry : flowPath.flowEntries()) {
357 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
358 }
359 modifiedFlowPaths.add(flowPath);
360 break;
361 }
362 newFlowPaths.add(flowPath);
363
364 break;
365 }
366
367 case ENTRY_REMOVE: {
368 //
369 // Remove an existing Flow Path.
370 //
371 // Find the Flow Path, and mark the Flow and its Flow Entries
372 // for deletion.
373 //
374 FlowPath existingFlowPath =
375 allFlowPaths.get(flowPath.flowId().value());
376 if (existingFlowPath == null)
377 continue; // Nothing to do
378
379 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
380 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
381 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
382 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
383 }
384
Yuta HIGUCHI2b5d0712013-10-30 15:48:13 -0700385 allFlowPaths.remove(existingFlowPath.flowId().value());
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700386 modifiedFlowPaths.add(existingFlowPath);
387
388 break;
389 }
390 }
391 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800392 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700393
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800394 /**
395 * Process the Topology events.
396 */
397 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700398 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800399 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700400 //
401 boolean isTopologyModified = false;
402 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
403 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800404
405 log.debug("Topology Event: {} {}", eventEntry.eventType(),
406 topologyElement.toString());
407
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700408 switch (eventEntry.eventType()) {
409 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700410 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700411 break;
412 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700413 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700414 break;
415 }
416 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700417 if (isTopologyModified) {
418 // TODO: For now, if the topology changes, we recompute all Flows
419 recomputeFlowPaths.addAll(allFlowPaths.values());
420 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800421 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700422
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800423 /**
424 * Process the Flow Entry events.
425 */
426 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800427 FlowPathEntryPair flowPair;
428 FlowPath flowPath;
429 FlowEntry updatedFlowEntry;
430
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700431 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800432 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700433 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800434 if (! unmatchedFlowEntryAdd.isEmpty()) {
435 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
436 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
437 flowPath = allFlowPaths.get(flowEntry.flowId().value());
438 if (flowPath == null)
439 continue;
440 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
441 if (updatedFlowEntry == null) {
442 remainingUpdates.put(flowEntry.flowEntryId().value(),
443 flowEntry);
444 continue;
445 }
446 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
447 updatedFlowEntries.add(flowPair);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700448 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800449 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700450 }
451
452 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800453 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700454 //
455 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
456 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800457
458 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
459 flowEntry.toString());
460
461 if ((! flowEntry.isValidFlowId()) ||
462 (! flowEntry.isValidFlowEntryId())) {
463 continue;
464 }
465
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700466 switch (eventEntry.eventType()) {
467 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800468 flowPath = allFlowPaths.get(flowEntry.flowId().value());
469 if (flowPath == null) {
470 // Flow Path not found: keep the entry for later matching
471 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
472 flowEntry);
473 break;
474 }
475 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
476 if (updatedFlowEntry == null) {
477 // Flow Entry not found: keep the entry for later matching
478 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
479 flowEntry);
480 break;
481 }
482 // Add the updated entry to the list of updated Flow Entries
483 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
484 updatedFlowEntries.add(flowPair);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700485 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800486
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700487 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800488 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
489 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
490 continue; // Match found
491 }
492
493 flowPath = allFlowPaths.get(flowEntry.flowId().value());
494 if (flowPath == null) {
495 // Flow Path not found: ignore the update
496 break;
497 }
498 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
499 if (updatedFlowEntry == null) {
500 // Flow Entry not found: add to list of deleted entries
501 flowPair = new FlowPathEntryPair(flowPath, flowEntry);
502 unmatchedDeleteFlowEntries.add(flowPair);
503 break;
504 }
505 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
506 updatedFlowEntries.add(flowPair);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700507 break;
508 }
509 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700510 }
511
512 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800513 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700514 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800515 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700516 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800517 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700518 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800519 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
520 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700521 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800522 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700523 //
524 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800525 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
526 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700527 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800528 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700529
530 //
531 // Local Flow Entry match found
532 //
533 if (localFlowEntry.isValidFlowEntryId()) {
534 if (localFlowEntry.flowEntryId().value() !=
535 flowEntry.flowEntryId().value()) {
536 //
537 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800538 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700539 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800540 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700541 }
542 } else {
543 // Update the Flow Entry ID
544 FlowEntryId flowEntryId =
545 new FlowEntryId(flowEntry.flowEntryId().value());
546 localFlowEntry.setFlowEntryId(flowEntryId);
547 }
548
549 //
550 // Update the local Flow Entry.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700551 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800552 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700553 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800554 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700555 }
556
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800557 return null; // Entry not found
558 }
559
560 /**
561 * Update a Flow Entry because of an external ENTRY_REMOVE event.
562 *
563 * @param flowPath the FlowPath for the Flow Entry to update.
564 * @param flowEntry the FlowEntry with the new state.
565 * @return the updated Flow Entry if found, otherwise null.
566 */
567 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
568 FlowEntry flowEntry) {
569 //
570 // Iterate over all Flow Entries and find a match based on
571 // the Flow Entry ID.
572 //
573 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
574 if (! localFlowEntry.isValidFlowEntryId())
575 continue;
576 if (localFlowEntry.flowEntryId().value() !=
577 flowEntry.flowEntryId().value()) {
578 continue;
579 }
580 //
581 // Update the local Flow Entry.
582 //
583 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
584 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
585 return localFlowEntry;
586 }
587
588 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700589 }
590
591 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700592 * Recompute a Flow Path.
593 *
594 * @param flowPath the Flow Path to recompute.
595 * @return true if the recomputed Flow Path has changed, otherwise false.
596 */
597 private boolean recomputeFlowPath(FlowPath flowPath) {
598 boolean hasChanged = false;
599
600 //
601 // Test whether the Flow Path needs to be recomputed
602 //
603 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700604 case FP_TYPE_UNKNOWN:
605 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700606 case FP_TYPE_SHORTEST_PATH:
607 break;
608 case FP_TYPE_EXPLICIT_PATH:
609 return false; // An explicit path never changes
610 }
611
612 DataPath oldDataPath = flowPath.dataPath();
613
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700614 // Compute the new path
615 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
616 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700617 if (newDataPath == null) {
618 // We need the DataPath to compare the paths
619 newDataPath = new DataPath();
620 }
621 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
622
623 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700624 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700625 //
626 if (oldDataPath.flowEntries().size() !=
627 newDataPath.flowEntries().size()) {
628 hasChanged = true;
629 } else {
630 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
631 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
632 while (oldIter.hasNext() && newIter.hasNext()) {
633 FlowEntry oldFlowEntry = oldIter.next();
634 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700635 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
636 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700637 hasChanged = true;
638 break;
639 }
640 }
641 }
642 if (! hasChanged)
643 return hasChanged;
644
645 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700646 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700647 // - If a Flow Entry for a switch is in the old data path, but not
648 // in the new data path, then mark it for deletion.
649 // - If a Flow Entry for a switch is in the new data path, but not
650 // in the old data path, then mark it for addition.
651 // - If a Flow Entry for a switch is in both the old and the new
652 // data path, but it has changed, e.g., the incoming and/or outgoing
653 // port(s), then mark the old Flow Entry for deletion, and mark
654 // the new Flow Entry for addition.
655 // - If a Flow Entry for a switch is in both the old and the new
656 // data path, and it hasn't changed, then just keep it.
657 //
658 // NOTE: We use the Switch DPID of each entry to match the entries
659 //
660 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
661 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
662 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
663 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
664
665 // Prepare maps with the Flow Entries, so they are fast to lookup
666 for (FlowEntry flowEntry : oldDataPath.flowEntries())
667 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
668 for (FlowEntry flowEntry : newDataPath.flowEntries())
669 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
670
671 //
672 // Find the old Flow Entries that should be deleted
673 //
674 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
675 FlowEntry newFlowEntry =
676 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
677 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800678 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700679 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
680 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
681 deletedFlowEntries.add(oldFlowEntry);
682 }
683 }
684
685 //
686 // Find the new Flow Entries that should be added or updated
687 //
688 int idx = 0;
689 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
690 FlowEntry oldFlowEntry =
691 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
692
693 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700694 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
695 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700696 //
697 // Both Flow Entries are same
698 //
699 finalFlowEntries.add(oldFlowEntry);
700 idx++;
701 continue;
702 }
703
704 if (oldFlowEntry != null) {
705 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800706 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700707 //
708 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
709 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
710 deletedFlowEntries.add(oldFlowEntry);
711 }
712
713 //
714 // Add the new Flow Entry
715 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700716 //
717 // NOTE: Assign only the Flow ID.
718 // The Flow Entry ID is assigned later only for the Flow Entries
719 // this instance is responsible for.
720 //
721 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700722
723 // Set the incoming port matching
724 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
725 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
726 flowEntryMatch.enableInPort(newFlowEntry.inPort());
727
728 //
729 // Set the actions:
730 // If the first Flow Entry, copy the Flow Path actions to it.
731 //
732 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
733 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
734 FlowEntryActions flowActions =
735 new FlowEntryActions(flowPath.flowEntryActions());
736 for (FlowEntryAction action : flowActions.actions())
737 flowEntryActions.addAction(action);
738 }
739 idx++;
740
741 //
742 // Add the outgoing port output action
743 //
744 FlowEntryAction flowEntryAction = new FlowEntryAction();
745 flowEntryAction.setActionOutput(newFlowEntry.outPort());
746 flowEntryActions.addAction(flowEntryAction);
747
748 //
749 // Set the state of the new Flow Entry
750 //
751 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
752 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
753 finalFlowEntries.add(newFlowEntry);
754 }
755
756 //
757 // Replace the old Flow Entries with the new Flow Entries.
758 // Note that the Flow Entries that will be deleted are added at
759 // the end.
760 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800761 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700762 flowPath.dataPath().setFlowEntries(finalFlowEntries);
763
764 return hasChanged;
765 }
766
767 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700768 * Receive a notification that a Flow is added.
769 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700770 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700771 */
772 @Override
773 public void notificationRecvFlowAdded(FlowPath flowPath) {
774 EventEntry<FlowPath> eventEntry =
775 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
776 networkEvents.add(eventEntry);
777 }
778
779 /**
780 * Receive a notification that a Flow is removed.
781 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700782 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700783 */
784 @Override
785 public void notificationRecvFlowRemoved(FlowPath flowPath) {
786 EventEntry<FlowPath> eventEntry =
787 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
788 networkEvents.add(eventEntry);
789 }
790
791 /**
792 * Receive a notification that a Flow is updated.
793 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700794 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700795 */
796 @Override
797 public void notificationRecvFlowUpdated(FlowPath flowPath) {
798 // NOTE: The ADD and UPDATE events are processed in same way
799 EventEntry<FlowPath> eventEntry =
800 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
801 networkEvents.add(eventEntry);
802 }
803
804 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700805 * Receive a notification that a FlowEntry is added.
806 *
807 * @param flowEntry the FlowEntry that is added.
808 */
809 @Override
810 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
811 EventEntry<FlowEntry> eventEntry =
812 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
813 networkEvents.add(eventEntry);
814 }
815
816 /**
817 * Receive a notification that a FlowEntry is removed.
818 *
819 * @param flowEntry the FlowEntry that is removed.
820 */
821 @Override
822 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
823 EventEntry<FlowEntry> eventEntry =
824 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
825 networkEvents.add(eventEntry);
826 }
827
828 /**
829 * Receive a notification that a FlowEntry is updated.
830 *
831 * @param flowEntry the FlowEntry that is updated.
832 */
833 @Override
834 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
835 // NOTE: The ADD and UPDATE events are processed in same way
836 EventEntry<FlowEntry> eventEntry =
837 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
838 networkEvents.add(eventEntry);
839 }
840
841 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700842 * Receive a notification that a Topology Element is added.
843 *
844 * @param topologyElement the Topology Element that is added.
845 */
846 @Override
847 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
848 EventEntry<TopologyElement> eventEntry =
849 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
850 networkEvents.add(eventEntry);
851 }
852
853 /**
854 * Receive a notification that a Topology Element is removed.
855 *
856 * @param topologyElement the Topology Element that is removed.
857 */
858 @Override
859 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
860 EventEntry<TopologyElement> eventEntry =
861 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
862 networkEvents.add(eventEntry);
863 }
864
865 /**
866 * Receive a notification that a Topology Element is updated.
867 *
868 * @param topologyElement the Topology Element that is updated.
869 */
870 @Override
871 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
872 // NOTE: The ADD and UPDATE events are processed in same way
873 EventEntry<TopologyElement> eventEntry =
874 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
875 networkEvents.add(eventEntry);
876 }
877}