blob: a750e1ea6c2ecc22bff7c454b2c188407d04e679 [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 Radoslavov6b79f2b2013-10-26 21:31:10 -070048
49 // The queue with Flow Path and Topology Element updates
50 private BlockingQueue<EventEntry<?>> networkEvents =
51 new LinkedBlockingQueue<EventEntry<?>>();
52
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070053 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070054 private List<EventEntry<TopologyElement>> topologyEvents =
55 new LinkedList<EventEntry<TopologyElement>>();
56 private List<EventEntry<FlowPath>> flowPathEvents =
57 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070058 private List<EventEntry<FlowEntry>> flowEntryEvents =
59 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070060
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080061 // All internally computed Flow Paths
62 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
63
64 // The Flow Entries received as notifications with unmatched Flow Paths
65 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
66 new HashMap<Long, FlowEntry>();
67
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080068 //
69 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080070 // - The Flow Paths that should be recomputed
71 // - The Flow Paths with modified Flow Entries
72 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080073 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
74 new HashMap<Long, FlowPath>();
75 private Map<Long, FlowPath> modifiedFlowPaths =
76 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080077
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070078 /**
79 * Constructor for a given Flow Manager and Datagrid Service.
80 *
81 * @param flowManager the Flow Manager to use.
82 * @param datagridService the Datagrid Service to use.
83 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070084 FlowEventHandler(FlowManager flowManager,
85 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070086 this.flowManager = flowManager;
87 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070088 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070089 }
90
91 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -080092 * Get the network topology.
93 *
94 * @return the network topology.
95 */
96 protected Topology getTopology() { return this.topology; }
97
98 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080099 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700100 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800101 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700102 //
103 // Obtain the initial Topology state
104 //
105 Collection<TopologyElement> topologyElements =
106 datagridService.getAllTopologyElements();
107 for (TopologyElement topologyElement : topologyElements) {
108 EventEntry<TopologyElement> eventEntry =
109 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
110 topologyEvents.add(eventEntry);
111 }
112 //
113 // Obtain the initial Flow Path state
114 //
115 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
116 for (FlowPath flowPath : flowPaths) {
117 EventEntry<FlowPath> eventEntry =
118 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
119 flowPathEvents.add(eventEntry);
120 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700121 //
122 // Obtain the initial FlowEntry state
123 //
124 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
125 for (FlowEntry flowEntry : flowEntries) {
126 EventEntry<FlowEntry> eventEntry =
127 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
128 flowEntryEvents.add(eventEntry);
129 }
130
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800131 // Process the initial events (if any)
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700132 processEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800133 }
134
135 /**
136 * Run the thread.
137 */
138 @Override
139 public void run() {
140 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700141
142 //
143 // The main loop
144 //
145 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
146 try {
147 while (true) {
148 EventEntry<?> eventEntry = networkEvents.take();
149 collection.add(eventEntry);
150 networkEvents.drainTo(collection);
151
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700152 //
153 // Demultiplex all events:
154 // - EventEntry<TopologyElement>
155 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700156 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700157 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700158 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800159 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700160 if (event.eventData() instanceof TopologyElement) {
161 EventEntry<TopologyElement> topologyEventEntry =
162 (EventEntry<TopologyElement>)event;
163 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800164 continue;
165 }
166
167 // FlowPath event
168 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700169 EventEntry<FlowPath> flowPathEventEntry =
170 (EventEntry<FlowPath>)event;
171 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800172 continue;
173 }
174
175 // FlowEntry event
176 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700177 EventEntry<FlowEntry> flowEntryEventEntry =
178 (EventEntry<FlowEntry>)event;
179 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800180 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700181 }
182 }
183 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700184
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700185 // Process the events (if any)
186 processEvents();
187 }
188 } catch (Exception exception) {
189 log.debug("Exception processing Network Events: ", exception);
190 }
191 }
192
193 /**
194 * Process the events (if any)
195 */
196 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800197 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700198
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700199 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
200 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700201 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700202 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700203
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800204 processFlowPathEvents();
205 processTopologyEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800206 processFlowEntryEvents();
207
208 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800209 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800210 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800211 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800212 }
213
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800214 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800215 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800216
217 // Assign missing Flow Entry IDs
218 assignFlowEntryId(modifiedFlowEntries);
219
220 //
221 // Push the modified Flow Entries to switches, datagrid and database
222 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800223 flowManager.pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800224 flowManager.pushModifiedFlowEntriesToDatagrid(modifiedFlowEntries);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800225 flowManager.pushModifiedFlowPathsToDatabase(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800226
227 //
228 // Remove Flow Entries that were deleted
229 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800230 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800231 flowPath.dataPath().removeDeletedFlowEntries();
232
233 // Cleanup
234 topologyEvents.clear();
235 flowPathEvents.clear();
236 flowEntryEvents.clear();
237 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800238 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800239 modifiedFlowPaths.clear();
240 }
241
242 /**
243 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800244 *
245 * @param modifiedFlowPaths the Flow Paths to process.
246 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800247 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800248 private Collection<FlowEntry> extractModifiedFlowEntries(
249 Collection<FlowPath> modifiedFlowPaths) {
250 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800251
252 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800253 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800254 for (FlowEntry flowEntry : flowPath.flowEntries()) {
255 if (flowEntry.flowEntrySwitchState() ==
256 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800257 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800258 }
259 }
260 }
261 return modifiedFlowEntries;
262 }
263
264 /**
265 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800266 *
267 * @param modifiedFlowEnries the collection of Flow Entries that need
268 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800269 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800270 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800271 if (modifiedFlowEntries.isEmpty())
272 return;
273
274 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
275
276 //
277 // Assign the Flow Entry ID only for Flow Entries for my switches
278 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800279 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800280 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
281 if (mySwitch == null)
282 continue;
283 if (! flowEntry.isValidFlowEntryId()) {
284 long id = flowManager.getNextFlowEntryId();
285 flowEntry.setFlowEntryId(new FlowEntryId(id));
286 }
287 }
288 }
289
290 /**
291 * Process the Flow Path events.
292 */
293 private void processFlowPathEvents() {
294 //
295 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700296 //
297 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
298 FlowPath flowPath = eventEntry.eventData();
299
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800300 log.debug("Flow Event: {} {}", eventEntry.eventType(),
301 flowPath.toString());
302
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700303 switch (eventEntry.eventType()) {
304 case ENTRY_ADD: {
305 //
306 // Add a new Flow Path
307 //
308 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
309 //
310 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800311 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700312 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700313 }
314
315 switch (flowPath.flowPathType()) {
316 case FP_TYPE_SHORTEST_PATH:
317 //
318 // Reset the Data Path, in case it was set already, because
319 // we are going to recompute it anyway.
320 //
321 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800322 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
323 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700324 break;
325 case FP_TYPE_EXPLICIT_PATH:
326 //
327 // Mark all Flow Entries for installation in the switches.
328 //
329 for (FlowEntry flowEntry : flowPath.flowEntries()) {
330 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
331 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800332 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700333 break;
334 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800335 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700336
337 break;
338 }
339
340 case ENTRY_REMOVE: {
341 //
342 // Remove an existing Flow Path.
343 //
344 // Find the Flow Path, and mark the Flow and its Flow Entries
345 // for deletion.
346 //
347 FlowPath existingFlowPath =
348 allFlowPaths.get(flowPath.flowId().value());
349 if (existingFlowPath == null)
350 continue; // Nothing to do
351
352 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
353 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
354 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
355 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
356 }
357
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800358 // Remove the Flow Path from the internal state
359 Long key = existingFlowPath.flowId().value();
360 allFlowPaths.remove(key);
361 shouldRecomputeFlowPaths.remove(key);
362 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700363
364 break;
365 }
366 }
367 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800368 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700369
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800370 /**
371 * Process the Topology events.
372 */
373 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700374 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800375 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700376 //
377 boolean isTopologyModified = false;
378 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
379 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800380
381 log.debug("Topology Event: {} {}", eventEntry.eventType(),
382 topologyElement.toString());
383
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700384 switch (eventEntry.eventType()) {
385 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700386 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700387 break;
388 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700389 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700390 break;
391 }
392 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700393 if (isTopologyModified) {
394 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800395 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700396 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800397 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700398
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800399 /**
400 * Process the Flow Entry events.
401 */
402 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800403 FlowPath flowPath;
404 FlowEntry updatedFlowEntry;
405
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700406 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800407 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700408 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800409 if (! unmatchedFlowEntryAdd.isEmpty()) {
410 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
411 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
412 flowPath = allFlowPaths.get(flowEntry.flowId().value());
413 if (flowPath == null)
414 continue;
415 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
416 if (updatedFlowEntry == null) {
417 remainingUpdates.put(flowEntry.flowEntryId().value(),
418 flowEntry);
419 continue;
420 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800421 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700422 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800423 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700424 }
425
426 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800427 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700428 //
429 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
430 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800431
432 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
433 flowEntry.toString());
434
435 if ((! flowEntry.isValidFlowId()) ||
436 (! flowEntry.isValidFlowEntryId())) {
437 continue;
438 }
439
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700440 switch (eventEntry.eventType()) {
441 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800442 flowPath = allFlowPaths.get(flowEntry.flowId().value());
443 if (flowPath == null) {
444 // Flow Path not found: keep the entry for later matching
445 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
446 flowEntry);
447 break;
448 }
449 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
450 if (updatedFlowEntry == null) {
451 // Flow Entry not found: keep the entry for later matching
452 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
453 flowEntry);
454 break;
455 }
456 // Add the updated entry to the list of updated Flow Entries
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800457 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700458 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800459
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700460 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800461 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
462 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800463 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800464 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800465
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800466 flowPath = allFlowPaths.get(flowEntry.flowId().value());
467 if (flowPath == null) {
468 // Flow Path not found: ignore the update
469 break;
470 }
471 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
472 if (updatedFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800473 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800474 break;
475 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800476 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700477 break;
478 }
479 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700480 }
481
482 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800483 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700484 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800485 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700486 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800487 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700488 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800489 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
490 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700491 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800492 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700493 //
494 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800495 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
496 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700497 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800498 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700499
500 //
501 // Local Flow Entry match found
502 //
503 if (localFlowEntry.isValidFlowEntryId()) {
504 if (localFlowEntry.flowEntryId().value() !=
505 flowEntry.flowEntryId().value()) {
506 //
507 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800508 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700509 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800510 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700511 }
512 } else {
513 // Update the Flow Entry ID
514 FlowEntryId flowEntryId =
515 new FlowEntryId(flowEntry.flowEntryId().value());
516 localFlowEntry.setFlowEntryId(flowEntryId);
517 }
518
519 //
520 // Update the local Flow Entry.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700521 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800522 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700523 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800524 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700525 }
526
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800527 return null; // Entry not found
528 }
529
530 /**
531 * Update a Flow Entry because of an external ENTRY_REMOVE event.
532 *
533 * @param flowPath the FlowPath for the Flow Entry to update.
534 * @param flowEntry the FlowEntry with the new state.
535 * @return the updated Flow Entry if found, otherwise null.
536 */
537 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
538 FlowEntry flowEntry) {
539 //
540 // Iterate over all Flow Entries and find a match based on
541 // the Flow Entry ID.
542 //
543 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
544 if (! localFlowEntry.isValidFlowEntryId())
545 continue;
546 if (localFlowEntry.flowEntryId().value() !=
547 flowEntry.flowEntryId().value()) {
548 continue;
549 }
550 //
551 // Update the local Flow Entry.
552 //
553 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
554 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
555 return localFlowEntry;
556 }
557
558 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700559 }
560
561 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700562 * Recompute a Flow Path.
563 *
564 * @param flowPath the Flow Path to recompute.
565 * @return true if the recomputed Flow Path has changed, otherwise false.
566 */
567 private boolean recomputeFlowPath(FlowPath flowPath) {
568 boolean hasChanged = false;
569
570 //
571 // Test whether the Flow Path needs to be recomputed
572 //
573 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700574 case FP_TYPE_UNKNOWN:
575 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700576 case FP_TYPE_SHORTEST_PATH:
577 break;
578 case FP_TYPE_EXPLICIT_PATH:
579 return false; // An explicit path never changes
580 }
581
582 DataPath oldDataPath = flowPath.dataPath();
583
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700584 // Compute the new path
585 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
586 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700587 if (newDataPath == null) {
588 // We need the DataPath to compare the paths
589 newDataPath = new DataPath();
590 }
591 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
592
593 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700594 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700595 //
596 if (oldDataPath.flowEntries().size() !=
597 newDataPath.flowEntries().size()) {
598 hasChanged = true;
599 } else {
600 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
601 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
602 while (oldIter.hasNext() && newIter.hasNext()) {
603 FlowEntry oldFlowEntry = oldIter.next();
604 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700605 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
606 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700607 hasChanged = true;
608 break;
609 }
610 }
611 }
612 if (! hasChanged)
613 return hasChanged;
614
615 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700616 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700617 // - If a Flow Entry for a switch is in the old data path, but not
618 // in the new data path, then mark it for deletion.
619 // - If a Flow Entry for a switch is in the new data path, but not
620 // in the old data path, then mark it for addition.
621 // - If a Flow Entry for a switch is in both the old and the new
622 // data path, but it has changed, e.g., the incoming and/or outgoing
623 // port(s), then mark the old Flow Entry for deletion, and mark
624 // the new Flow Entry for addition.
625 // - If a Flow Entry for a switch is in both the old and the new
626 // data path, and it hasn't changed, then just keep it.
627 //
628 // NOTE: We use the Switch DPID of each entry to match the entries
629 //
630 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
631 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
632 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
633 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
634
635 // Prepare maps with the Flow Entries, so they are fast to lookup
636 for (FlowEntry flowEntry : oldDataPath.flowEntries())
637 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
638 for (FlowEntry flowEntry : newDataPath.flowEntries())
639 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
640
641 //
642 // Find the old Flow Entries that should be deleted
643 //
644 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
645 FlowEntry newFlowEntry =
646 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
647 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800648 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700649 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
650 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
651 deletedFlowEntries.add(oldFlowEntry);
652 }
653 }
654
655 //
656 // Find the new Flow Entries that should be added or updated
657 //
658 int idx = 0;
659 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
660 FlowEntry oldFlowEntry =
661 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
662
663 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700664 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
665 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700666 //
667 // Both Flow Entries are same
668 //
669 finalFlowEntries.add(oldFlowEntry);
670 idx++;
671 continue;
672 }
673
674 if (oldFlowEntry != null) {
675 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800676 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700677 //
678 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
679 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
680 deletedFlowEntries.add(oldFlowEntry);
681 }
682
683 //
684 // Add the new Flow Entry
685 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700686 //
687 // NOTE: Assign only the Flow ID.
688 // The Flow Entry ID is assigned later only for the Flow Entries
689 // this instance is responsible for.
690 //
691 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700692
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800693 //
694 // Allocate the FlowEntryMatch by copying the default one
695 // from the FlowPath (if set).
696 //
697 FlowEntryMatch flowEntryMatch = null;
698 if (flowPath.flowEntryMatch() != null)
699 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
700 else
701 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700702 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800703
704 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700705 flowEntryMatch.enableInPort(newFlowEntry.inPort());
706
707 //
708 // Set the actions:
709 // If the first Flow Entry, copy the Flow Path actions to it.
710 //
711 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
712 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
713 FlowEntryActions flowActions =
714 new FlowEntryActions(flowPath.flowEntryActions());
715 for (FlowEntryAction action : flowActions.actions())
716 flowEntryActions.addAction(action);
717 }
718 idx++;
719
720 //
721 // Add the outgoing port output action
722 //
723 FlowEntryAction flowEntryAction = new FlowEntryAction();
724 flowEntryAction.setActionOutput(newFlowEntry.outPort());
725 flowEntryActions.addAction(flowEntryAction);
726
727 //
728 // Set the state of the new Flow Entry
729 //
730 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
731 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
732 finalFlowEntries.add(newFlowEntry);
733 }
734
735 //
736 // Replace the old Flow Entries with the new Flow Entries.
737 // Note that the Flow Entries that will be deleted are added at
738 // the end.
739 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800740 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700741 flowPath.dataPath().setFlowEntries(finalFlowEntries);
742
743 return hasChanged;
744 }
745
746 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700747 * Receive a notification that a Flow is added.
748 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700749 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700750 */
751 @Override
752 public void notificationRecvFlowAdded(FlowPath flowPath) {
753 EventEntry<FlowPath> eventEntry =
754 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
755 networkEvents.add(eventEntry);
756 }
757
758 /**
759 * Receive a notification that a Flow is removed.
760 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700761 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700762 */
763 @Override
764 public void notificationRecvFlowRemoved(FlowPath flowPath) {
765 EventEntry<FlowPath> eventEntry =
766 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
767 networkEvents.add(eventEntry);
768 }
769
770 /**
771 * Receive a notification that a Flow is updated.
772 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700773 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700774 */
775 @Override
776 public void notificationRecvFlowUpdated(FlowPath flowPath) {
777 // NOTE: The ADD and UPDATE events are processed in same way
778 EventEntry<FlowPath> eventEntry =
779 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
780 networkEvents.add(eventEntry);
781 }
782
783 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700784 * Receive a notification that a FlowEntry is added.
785 *
786 * @param flowEntry the FlowEntry that is added.
787 */
788 @Override
789 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
790 EventEntry<FlowEntry> eventEntry =
791 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
792 networkEvents.add(eventEntry);
793 }
794
795 /**
796 * Receive a notification that a FlowEntry is removed.
797 *
798 * @param flowEntry the FlowEntry that is removed.
799 */
800 @Override
801 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
802 EventEntry<FlowEntry> eventEntry =
803 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
804 networkEvents.add(eventEntry);
805 }
806
807 /**
808 * Receive a notification that a FlowEntry is updated.
809 *
810 * @param flowEntry the FlowEntry that is updated.
811 */
812 @Override
813 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
814 // NOTE: The ADD and UPDATE events are processed in same way
815 EventEntry<FlowEntry> eventEntry =
816 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
817 networkEvents.add(eventEntry);
818 }
819
820 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700821 * Receive a notification that a Topology Element is added.
822 *
823 * @param topologyElement the Topology Element that is added.
824 */
825 @Override
826 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
827 EventEntry<TopologyElement> eventEntry =
828 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
829 networkEvents.add(eventEntry);
830 }
831
832 /**
833 * Receive a notification that a Topology Element is removed.
834 *
835 * @param topologyElement the Topology Element that is removed.
836 */
837 @Override
838 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
839 EventEntry<TopologyElement> eventEntry =
840 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
841 networkEvents.add(eventEntry);
842 }
843
844 /**
845 * Receive a notification that a Topology Element is updated.
846 *
847 * @param topologyElement the Topology Element that is updated.
848 */
849 @Override
850 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
851 // NOTE: The ADD and UPDATE events are processed in same way
852 EventEntry<TopologyElement> eventEntry =
853 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
854 networkEvents.add(eventEntry);
855 }
856}