blob: 47ef3b78d68696f24b99c1df7240ec2edcf75e09 [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 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800221 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800222 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800223 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
224 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800225
226 //
227 // Remove Flow Entries that were deleted
228 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800229 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800230 flowPath.dataPath().removeDeletedFlowEntries();
231
232 // Cleanup
233 topologyEvents.clear();
234 flowPathEvents.clear();
235 flowEntryEvents.clear();
236 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800237 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800238 modifiedFlowPaths.clear();
239 }
240
241 /**
242 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800243 *
244 * @param modifiedFlowPaths the Flow Paths to process.
245 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800246 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800247 private Collection<FlowEntry> extractModifiedFlowEntries(
248 Collection<FlowPath> modifiedFlowPaths) {
249 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800250
251 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800252 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800253 for (FlowEntry flowEntry : flowPath.flowEntries()) {
254 if (flowEntry.flowEntrySwitchState() ==
255 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800256 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800257 }
258 }
259 }
260 return modifiedFlowEntries;
261 }
262
263 /**
264 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800265 *
266 * @param modifiedFlowEnries the collection of Flow Entries that need
267 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800268 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800269 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800270 if (modifiedFlowEntries.isEmpty())
271 return;
272
273 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
274
275 //
276 // Assign the Flow Entry ID only for Flow Entries for my switches
277 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800278 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800279 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
280 if (mySwitch == null)
281 continue;
282 if (! flowEntry.isValidFlowEntryId()) {
283 long id = flowManager.getNextFlowEntryId();
284 flowEntry.setFlowEntryId(new FlowEntryId(id));
285 }
286 }
287 }
288
289 /**
290 * Process the Flow Path events.
291 */
292 private void processFlowPathEvents() {
293 //
294 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700295 //
296 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
297 FlowPath flowPath = eventEntry.eventData();
298
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800299 log.debug("Flow Event: {} {}", eventEntry.eventType(),
300 flowPath.toString());
301
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700302 switch (eventEntry.eventType()) {
303 case ENTRY_ADD: {
304 //
305 // Add a new Flow Path
306 //
307 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
308 //
309 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800310 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700311 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700312 }
313
314 switch (flowPath.flowPathType()) {
315 case FP_TYPE_SHORTEST_PATH:
316 //
317 // Reset the Data Path, in case it was set already, because
318 // we are going to recompute it anyway.
319 //
320 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800321 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
322 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700323 break;
324 case FP_TYPE_EXPLICIT_PATH:
325 //
326 // Mark all Flow Entries for installation in the switches.
327 //
328 for (FlowEntry flowEntry : flowPath.flowEntries()) {
329 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
330 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800331 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700332 break;
333 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800334 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700335
336 break;
337 }
338
339 case ENTRY_REMOVE: {
340 //
341 // Remove an existing Flow Path.
342 //
343 // Find the Flow Path, and mark the Flow and its Flow Entries
344 // for deletion.
345 //
346 FlowPath existingFlowPath =
347 allFlowPaths.get(flowPath.flowId().value());
348 if (existingFlowPath == null)
349 continue; // Nothing to do
350
351 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
352 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
353 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
354 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
355 }
356
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800357 // Remove the Flow Path from the internal state
358 Long key = existingFlowPath.flowId().value();
359 allFlowPaths.remove(key);
360 shouldRecomputeFlowPaths.remove(key);
361 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700362
363 break;
364 }
365 }
366 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800367 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700368
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800369 /**
370 * Process the Topology events.
371 */
372 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700373 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800374 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700375 //
376 boolean isTopologyModified = false;
377 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
378 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800379
380 log.debug("Topology Event: {} {}", eventEntry.eventType(),
381 topologyElement.toString());
382
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700383 switch (eventEntry.eventType()) {
384 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700385 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700386 break;
387 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700388 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700389 break;
390 }
391 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700392 if (isTopologyModified) {
393 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800394 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700395 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800396 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700397
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800398 /**
399 * Process the Flow Entry events.
400 */
401 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800402 FlowPath flowPath;
403 FlowEntry updatedFlowEntry;
404
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700405 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800406 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700407 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800408 if (! unmatchedFlowEntryAdd.isEmpty()) {
409 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
410 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
411 flowPath = allFlowPaths.get(flowEntry.flowId().value());
412 if (flowPath == null)
413 continue;
414 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
415 if (updatedFlowEntry == null) {
416 remainingUpdates.put(flowEntry.flowEntryId().value(),
417 flowEntry);
418 continue;
419 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800420 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700421 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800422 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700423 }
424
425 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800426 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700427 //
428 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
429 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800430
431 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
432 flowEntry.toString());
433
434 if ((! flowEntry.isValidFlowId()) ||
435 (! flowEntry.isValidFlowEntryId())) {
436 continue;
437 }
438
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700439 switch (eventEntry.eventType()) {
440 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800441 flowPath = allFlowPaths.get(flowEntry.flowId().value());
442 if (flowPath == null) {
443 // Flow Path not found: keep the entry for later matching
444 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
445 flowEntry);
446 break;
447 }
448 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
449 if (updatedFlowEntry == null) {
450 // Flow Entry not found: keep the entry for later matching
451 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
452 flowEntry);
453 break;
454 }
455 // Add the updated entry to the list of updated Flow Entries
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800456 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700457 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800458
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700459 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800460 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
461 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800462 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800463 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800464
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800465 flowPath = allFlowPaths.get(flowEntry.flowId().value());
466 if (flowPath == null) {
467 // Flow Path not found: ignore the update
468 break;
469 }
470 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
471 if (updatedFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800472 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800473 break;
474 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800475 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700476 break;
477 }
478 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700479 }
480
481 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800482 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700483 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800484 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700485 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800486 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700487 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800488 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
489 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700490 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800491 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700492 //
493 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800494 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
495 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700496 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800497 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700498
499 //
500 // Local Flow Entry match found
501 //
502 if (localFlowEntry.isValidFlowEntryId()) {
503 if (localFlowEntry.flowEntryId().value() !=
504 flowEntry.flowEntryId().value()) {
505 //
506 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700508 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800509 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700510 }
511 } else {
512 // Update the Flow Entry ID
513 FlowEntryId flowEntryId =
514 new FlowEntryId(flowEntry.flowEntryId().value());
515 localFlowEntry.setFlowEntryId(flowEntryId);
516 }
517
518 //
519 // Update the local Flow Entry.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700520 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800521 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700522 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800523 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700524 }
525
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800526 return null; // Entry not found
527 }
528
529 /**
530 * Update a Flow Entry because of an external ENTRY_REMOVE event.
531 *
532 * @param flowPath the FlowPath for the Flow Entry to update.
533 * @param flowEntry the FlowEntry with the new state.
534 * @return the updated Flow Entry if found, otherwise null.
535 */
536 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
537 FlowEntry flowEntry) {
538 //
539 // Iterate over all Flow Entries and find a match based on
540 // the Flow Entry ID.
541 //
542 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
543 if (! localFlowEntry.isValidFlowEntryId())
544 continue;
545 if (localFlowEntry.flowEntryId().value() !=
546 flowEntry.flowEntryId().value()) {
547 continue;
548 }
549 //
550 // Update the local Flow Entry.
551 //
552 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
553 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
554 return localFlowEntry;
555 }
556
557 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700558 }
559
560 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700561 * Recompute a Flow Path.
562 *
563 * @param flowPath the Flow Path to recompute.
564 * @return true if the recomputed Flow Path has changed, otherwise false.
565 */
566 private boolean recomputeFlowPath(FlowPath flowPath) {
567 boolean hasChanged = false;
568
569 //
570 // Test whether the Flow Path needs to be recomputed
571 //
572 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700573 case FP_TYPE_UNKNOWN:
574 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700575 case FP_TYPE_SHORTEST_PATH:
576 break;
577 case FP_TYPE_EXPLICIT_PATH:
578 return false; // An explicit path never changes
579 }
580
581 DataPath oldDataPath = flowPath.dataPath();
582
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700583 // Compute the new path
584 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
585 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700586 if (newDataPath == null) {
587 // We need the DataPath to compare the paths
588 newDataPath = new DataPath();
589 }
590 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
591
592 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700593 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700594 //
595 if (oldDataPath.flowEntries().size() !=
596 newDataPath.flowEntries().size()) {
597 hasChanged = true;
598 } else {
599 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
600 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
601 while (oldIter.hasNext() && newIter.hasNext()) {
602 FlowEntry oldFlowEntry = oldIter.next();
603 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700604 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
605 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700606 hasChanged = true;
607 break;
608 }
609 }
610 }
611 if (! hasChanged)
612 return hasChanged;
613
614 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700615 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700616 // - If a Flow Entry for a switch is in the old data path, but not
617 // in the new data path, then mark it for deletion.
618 // - If a Flow Entry for a switch is in the new data path, but not
619 // in the old data path, then mark it for addition.
620 // - If a Flow Entry for a switch is in both the old and the new
621 // data path, but it has changed, e.g., the incoming and/or outgoing
622 // port(s), then mark the old Flow Entry for deletion, and mark
623 // the new Flow Entry for addition.
624 // - If a Flow Entry for a switch is in both the old and the new
625 // data path, and it hasn't changed, then just keep it.
626 //
627 // NOTE: We use the Switch DPID of each entry to match the entries
628 //
629 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
630 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
631 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
632 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
633
634 // Prepare maps with the Flow Entries, so they are fast to lookup
635 for (FlowEntry flowEntry : oldDataPath.flowEntries())
636 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
637 for (FlowEntry flowEntry : newDataPath.flowEntries())
638 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
639
640 //
641 // Find the old Flow Entries that should be deleted
642 //
643 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
644 FlowEntry newFlowEntry =
645 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
646 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800647 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700648 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
649 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
650 deletedFlowEntries.add(oldFlowEntry);
651 }
652 }
653
654 //
655 // Find the new Flow Entries that should be added or updated
656 //
657 int idx = 0;
658 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
659 FlowEntry oldFlowEntry =
660 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
661
662 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700663 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
664 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700665 //
666 // Both Flow Entries are same
667 //
668 finalFlowEntries.add(oldFlowEntry);
669 idx++;
670 continue;
671 }
672
673 if (oldFlowEntry != null) {
674 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800675 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700676 //
677 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
678 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
679 deletedFlowEntries.add(oldFlowEntry);
680 }
681
682 //
683 // Add the new Flow Entry
684 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700685 //
686 // NOTE: Assign only the Flow ID.
687 // The Flow Entry ID is assigned later only for the Flow Entries
688 // this instance is responsible for.
689 //
690 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700691
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800692 //
693 // Allocate the FlowEntryMatch by copying the default one
694 // from the FlowPath (if set).
695 //
696 FlowEntryMatch flowEntryMatch = null;
697 if (flowPath.flowEntryMatch() != null)
698 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
699 else
700 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700701 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800702
703 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700704 flowEntryMatch.enableInPort(newFlowEntry.inPort());
705
706 //
707 // Set the actions:
708 // If the first Flow Entry, copy the Flow Path actions to it.
709 //
710 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
711 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
712 FlowEntryActions flowActions =
713 new FlowEntryActions(flowPath.flowEntryActions());
714 for (FlowEntryAction action : flowActions.actions())
715 flowEntryActions.addAction(action);
716 }
717 idx++;
718
719 //
720 // Add the outgoing port output action
721 //
722 FlowEntryAction flowEntryAction = new FlowEntryAction();
723 flowEntryAction.setActionOutput(newFlowEntry.outPort());
724 flowEntryActions.addAction(flowEntryAction);
725
726 //
727 // Set the state of the new Flow Entry
728 //
729 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
730 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
731 finalFlowEntries.add(newFlowEntry);
732 }
733
734 //
735 // Replace the old Flow Entries with the new Flow Entries.
736 // Note that the Flow Entries that will be deleted are added at
737 // the end.
738 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800739 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700740 flowPath.dataPath().setFlowEntries(finalFlowEntries);
741
742 return hasChanged;
743 }
744
745 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700746 * Receive a notification that a Flow is added.
747 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700748 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700749 */
750 @Override
751 public void notificationRecvFlowAdded(FlowPath flowPath) {
752 EventEntry<FlowPath> eventEntry =
753 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
754 networkEvents.add(eventEntry);
755 }
756
757 /**
758 * Receive a notification that a Flow is removed.
759 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700760 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700761 */
762 @Override
763 public void notificationRecvFlowRemoved(FlowPath flowPath) {
764 EventEntry<FlowPath> eventEntry =
765 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
766 networkEvents.add(eventEntry);
767 }
768
769 /**
770 * Receive a notification that a Flow is updated.
771 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700772 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700773 */
774 @Override
775 public void notificationRecvFlowUpdated(FlowPath flowPath) {
776 // NOTE: The ADD and UPDATE events are processed in same way
777 EventEntry<FlowPath> eventEntry =
778 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
779 networkEvents.add(eventEntry);
780 }
781
782 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700783 * Receive a notification that a FlowEntry is added.
784 *
785 * @param flowEntry the FlowEntry that is added.
786 */
787 @Override
788 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
789 EventEntry<FlowEntry> eventEntry =
790 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
791 networkEvents.add(eventEntry);
792 }
793
794 /**
795 * Receive a notification that a FlowEntry is removed.
796 *
797 * @param flowEntry the FlowEntry that is removed.
798 */
799 @Override
800 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
801 EventEntry<FlowEntry> eventEntry =
802 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
803 networkEvents.add(eventEntry);
804 }
805
806 /**
807 * Receive a notification that a FlowEntry is updated.
808 *
809 * @param flowEntry the FlowEntry that is updated.
810 */
811 @Override
812 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
813 // NOTE: The ADD and UPDATE events are processed in same way
814 EventEntry<FlowEntry> eventEntry =
815 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
816 networkEvents.add(eventEntry);
817 }
818
819 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700820 * Receive a notification that a Topology Element is added.
821 *
822 * @param topologyElement the Topology Element that is added.
823 */
824 @Override
825 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
826 EventEntry<TopologyElement> eventEntry =
827 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
828 networkEvents.add(eventEntry);
829 }
830
831 /**
832 * Receive a notification that a Topology Element is removed.
833 *
834 * @param topologyElement the Topology Element that is removed.
835 */
836 @Override
837 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
838 EventEntry<TopologyElement> eventEntry =
839 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
840 networkEvents.add(eventEntry);
841 }
842
843 /**
844 * Receive a notification that a Topology Element is updated.
845 *
846 * @param topologyElement the Topology Element that is updated.
847 */
848 @Override
849 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
850 // NOTE: The ADD and UPDATE events are processed in same way
851 EventEntry<TopologyElement> eventEntry =
852 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
853 networkEvents.add(eventEntry);
854 }
855}