blob: 68cd844bdc8c9af6ce3ba1efa5dfa542da32230d [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 Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
11import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.LinkedBlockingQueue;
14
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070016import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070017import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070019import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070020import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070021import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070022import net.onrc.onos.ofcontroller.util.FlowEntry;
23import net.onrc.onos.ofcontroller.util.FlowEntryAction;
24import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070025import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070026import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
27import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
28import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070029import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070030import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070031import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080032import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
33
34import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070035
36import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070040 * Class for FlowPath Maintenance.
41 * This class listens for FlowEvents to:
42 * - Maintain a local cache of the Network Topology.
43 * - Detect FlowPaths impacted by Topology change.
44 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070045 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070046class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070047 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070048 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070049
50 private FlowManager flowManager; // The Flow Manager to use
51 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070052 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080053 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070054
55 // The queue with Flow Path and Topology Element updates
56 private BlockingQueue<EventEntry<?>> networkEvents =
57 new LinkedBlockingQueue<EventEntry<?>>();
58
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070059 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070060 private List<EventEntry<TopologyElement>> topologyEvents =
61 new LinkedList<EventEntry<TopologyElement>>();
62 private List<EventEntry<FlowPath>> flowPathEvents =
63 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070064 private List<EventEntry<FlowEntry>> flowEntryEvents =
65 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070066
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080067 // All internally computed Flow Paths
68 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
69
70 // The Flow Entries received as notifications with unmatched Flow Paths
71 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
72 new HashMap<Long, FlowEntry>();
73
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080074 //
75 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080076 // - The Flow Paths that should be recomputed
77 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080078 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080079 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080080 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
81 new HashMap<Long, FlowPath>();
82 private Map<Long, FlowPath> modifiedFlowPaths =
83 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080084 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
85 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080086
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070087 /**
88 * Constructor for a given Flow Manager and Datagrid Service.
89 *
90 * @param flowManager the Flow Manager to use.
91 * @param datagridService the Datagrid Service to use.
92 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070093 FlowEventHandler(FlowManager flowManager,
94 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070095 this.flowManager = flowManager;
96 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070097 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070098 }
99
100 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800101 * Get the network topology.
102 *
103 * @return the network topology.
104 */
105 protected Topology getTopology() { return this.topology; }
106
107 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800108 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700109 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800110 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700111 //
112 // Obtain the initial Topology state
113 //
114 Collection<TopologyElement> topologyElements =
115 datagridService.getAllTopologyElements();
116 for (TopologyElement topologyElement : topologyElements) {
117 EventEntry<TopologyElement> eventEntry =
118 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
119 topologyEvents.add(eventEntry);
120 }
121 //
122 // Obtain the initial Flow Path state
123 //
124 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
125 for (FlowPath flowPath : flowPaths) {
126 EventEntry<FlowPath> eventEntry =
127 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
128 flowPathEvents.add(eventEntry);
129 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700130 //
131 // Obtain the initial FlowEntry state
132 //
133 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
134 for (FlowEntry flowEntry : flowEntries) {
135 EventEntry<FlowEntry> eventEntry =
136 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
137 flowEntryEvents.add(eventEntry);
138 }
139
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800140 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800141 synchronized (allFlowPaths) {
142 processEvents();
143 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800144 }
145
146 /**
147 * Run the thread.
148 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800149 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800150 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800151 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800152 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700153
154 //
155 // The main loop
156 //
157 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
158 try {
159 while (true) {
160 EventEntry<?> eventEntry = networkEvents.take();
161 collection.add(eventEntry);
162 networkEvents.drainTo(collection);
163
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700164 //
165 // Demultiplex all events:
166 // - EventEntry<TopologyElement>
167 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700168 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700169 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700170 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800171 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700172 if (event.eventData() instanceof TopologyElement) {
173 EventEntry<TopologyElement> topologyEventEntry =
174 (EventEntry<TopologyElement>)event;
175 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800176 continue;
177 }
178
179 // FlowPath event
180 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700181 EventEntry<FlowPath> flowPathEventEntry =
182 (EventEntry<FlowPath>)event;
183 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800184 continue;
185 }
186
187 // FlowEntry event
188 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700189 EventEntry<FlowEntry> flowEntryEventEntry =
190 (EventEntry<FlowEntry>)event;
191 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800192 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700193 }
194 }
195 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700196
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700197 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800198 synchronized (allFlowPaths) {
199 processEvents();
200 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700201 }
202 } catch (Exception exception) {
203 log.debug("Exception processing Network Events: ", exception);
204 }
205 }
206
207 /**
208 * Process the events (if any)
209 */
210 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800211 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700212
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700213 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
214 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700215 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700216 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700217
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800218 processFlowPathEvents();
219 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800220 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800221 processFlowEntryEvents();
222
223 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800224 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800225 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800226 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800227 }
228
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800229 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800230 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800231
232 // Assign missing Flow Entry IDs
233 assignFlowEntryId(modifiedFlowEntries);
234
235 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800236 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800237 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800238 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
239 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800240
241 //
242 // Remove Flow Entries that were deleted
243 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800244 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800245 flowPath.dataPath().removeDeletedFlowEntries();
246
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800247 //
248 // Check if Flow Paths have been installed into all switches,
249 // and generate the appropriate events.
250 //
251 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
252
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800253 // Cleanup
254 topologyEvents.clear();
255 flowPathEvents.clear();
256 flowEntryEvents.clear();
257 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800258 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800259 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800260 checkIfInstalledFlowPaths.clear();
261 }
262
263 /**
264 * Check if Flow Paths have been installed into all switches,
265 * and generate the appropriate events.
266 *
267 * @param flowPaths the flowPaths to process.
268 */
269 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
270 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
271
272 Kryo kryo = kryoFactory.newKryo();
273
274 for (FlowPath flowPath : flowPaths) {
275 boolean isInstalled = true;
Jonathan Hart0444d932014-01-22 15:06:17 -0800276
277 if (flowPath.flowEntries().isEmpty()) {
278 continue;
279 }
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800280
281 //
282 // Check whether all Flow Entries have been installed
283 //
284 for (FlowEntry flowEntry : flowPath.flowEntries()) {
285 if (flowEntry.flowEntrySwitchState() !=
286 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
287 isInstalled = false;
288 break;
289 }
290 }
291
292 if (isInstalled) {
293 // Create a copy and add it to the list
294 FlowPath copyFlowPath = kryo.copy(flowPath);
295 installedFlowPaths.add(copyFlowPath);
296 }
297 }
298 kryoFactory.deleteKryo(kryo);
299
300 // Generate an event for the installed Flow Path.
301 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800302 }
303
304 /**
305 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800306 *
307 * @param modifiedFlowPaths the Flow Paths to process.
308 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800309 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800310 private Collection<FlowEntry> extractModifiedFlowEntries(
311 Collection<FlowPath> modifiedFlowPaths) {
312 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800313
314 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800315 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800316 for (FlowEntry flowEntry : flowPath.flowEntries()) {
317 if (flowEntry.flowEntrySwitchState() ==
318 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800319 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800320 }
321 }
322 }
323 return modifiedFlowEntries;
324 }
325
326 /**
327 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800328 *
329 * @param modifiedFlowEnries the collection of Flow Entries that need
330 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800331 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800332 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800333 if (modifiedFlowEntries.isEmpty())
334 return;
335
336 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
337
338 //
339 // Assign the Flow Entry ID only for Flow Entries for my switches
340 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800341 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800342 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
343 if (mySwitch == null)
344 continue;
345 if (! flowEntry.isValidFlowEntryId()) {
346 long id = flowManager.getNextFlowEntryId();
347 flowEntry.setFlowEntryId(new FlowEntryId(id));
348 }
349 }
350 }
351
352 /**
353 * Process the Flow Path events.
354 */
355 private void processFlowPathEvents() {
356 //
357 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700358 //
359 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
360 FlowPath flowPath = eventEntry.eventData();
361
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800362 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800363
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700364 switch (eventEntry.eventType()) {
365 case ENTRY_ADD: {
366 //
367 // Add a new Flow Path
368 //
369 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
370 //
371 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800372 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700373 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700374 }
375
376 switch (flowPath.flowPathType()) {
377 case FP_TYPE_SHORTEST_PATH:
378 //
379 // Reset the Data Path, in case it was set already, because
380 // we are going to recompute it anyway.
381 //
382 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800383 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
384 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700385 break;
386 case FP_TYPE_EXPLICIT_PATH:
387 //
388 // Mark all Flow Entries for installation in the switches.
389 //
390 for (FlowEntry flowEntry : flowPath.flowEntries()) {
391 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
392 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800393 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700394 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800395 case FP_TYPE_UNKNOWN:
396 log.error("FlowPath event with unknown type");
397 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700398 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800399 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700400
401 break;
402 }
403
404 case ENTRY_REMOVE: {
405 //
406 // Remove an existing Flow Path.
407 //
408 // Find the Flow Path, and mark the Flow and its Flow Entries
409 // for deletion.
410 //
411 FlowPath existingFlowPath =
412 allFlowPaths.get(flowPath.flowId().value());
413 if (existingFlowPath == null)
414 continue; // Nothing to do
415
416 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
417 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
418 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
419 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
420 }
421
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800422 // Remove the Flow Path from the internal state
423 Long key = existingFlowPath.flowId().value();
424 allFlowPaths.remove(key);
425 shouldRecomputeFlowPaths.remove(key);
426 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700427
428 break;
429 }
430 }
431 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800432 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700433
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800434 /**
435 * Process the Topology events.
436 */
437 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700438 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800439 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700440 //
441 boolean isTopologyModified = false;
442 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
443 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800444
445 log.debug("Topology Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800446 topologyElement);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800447
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700448 switch (eventEntry.eventType()) {
449 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700450 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700451 break;
452 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700453 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700454 break;
455 }
456 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700457 if (isTopologyModified) {
458 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800459 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700460 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800461 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700462
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800463 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800464 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800465 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800466 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800467 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800468 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800469
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700470 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800471 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700472 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800473 if (! unmatchedFlowEntryAdd.isEmpty()) {
474 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
475 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800476 // log.debug("Processing Unmatched Flow Entry: {}",
477 // flowEntry.toString());
478
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800479 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800480 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800481 remainingUpdates.put(flowEntry.flowEntryId().value(),
482 flowEntry);
483 continue;
484 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800485 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
486 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800487 remainingUpdates.put(flowEntry.flowEntryId().value(),
488 flowEntry);
489 continue;
490 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800491 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
492 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
493 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700494 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800495 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700496 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800497 }
498
499 /**
500 * Process the Flow Entry events.
501 */
502 private void processFlowEntryEvents() {
503 FlowPath flowPath;
504 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700505
506 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800507 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700508 //
509 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
510 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800511
512 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800513 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800514
515 if ((! flowEntry.isValidFlowId()) ||
516 (! flowEntry.isValidFlowEntryId())) {
517 continue;
518 }
519
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700520 switch (eventEntry.eventType()) {
521 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800522 flowPath = allFlowPaths.get(flowEntry.flowId().value());
523 if (flowPath == null) {
524 // Flow Path not found: keep the entry for later matching
525 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
526 flowEntry);
527 break;
528 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800529 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
530 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800531 // Flow Entry not found: keep the entry for later matching
532 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
533 flowEntry);
534 break;
535 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800536 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
537 // Add the updated Flow Path to the list of updated paths
538 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
539 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700540 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800541
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700542 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800543 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
544 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800545 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800546 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800547
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800548 flowPath = allFlowPaths.get(flowEntry.flowId().value());
549 if (flowPath == null) {
550 // Flow Path not found: ignore the update
551 break;
552 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800553 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
554 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800555 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800556 break;
557 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800558 if (updateFlowEntryRemove(flowPath, localFlowEntry,
559 flowEntry)) {
560 // Add the updated Flow Path to the list of updated paths
561 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
562 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700563 break;
564 }
565 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700566 }
567
568 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800569 * Find a Flow Entry that should be updated because of an external
570 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700571 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800572 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800573 * @param newFlowEntry the FlowEntry with the new state.
574 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700575 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800576 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
577 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700578 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800579 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700580 //
581 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800582 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800583 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700584 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800585 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700586
587 //
588 // Local Flow Entry match found
589 //
590 if (localFlowEntry.isValidFlowEntryId()) {
591 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800592 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700593 //
594 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800595 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700596 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800597 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700598 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700599 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800600 return localFlowEntry;
601 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700602
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800603 return null; // Entry not found
604 }
605
606 /**
607 * Update a Flow Entry because of an external ENTRY_ADD event.
608 *
609 * @param flowPath the FlowPath for the Flow Entry to update.
610 * @param localFlowEntry the local Flow Entry to update.
611 * @param newFlowEntry the FlowEntry with the new state.
612 * @return true if the local Flow Entry was updated, otherwise false.
613 */
614 private boolean updateFlowEntryAdd(FlowPath flowPath,
615 FlowEntry localFlowEntry,
616 FlowEntry newFlowEntry) {
617 boolean updated = false;
618
619 if (localFlowEntry.flowEntryUserState() ==
620 FlowEntryUserState.FE_USER_DELETE) {
621 // Don't add-back a Flow Entry that is already deleted
622 return false;
623 }
624
625 if (! localFlowEntry.isValidFlowEntryId()) {
626 // Update the Flow Entry ID
627 FlowEntryId flowEntryId =
628 new FlowEntryId(newFlowEntry.flowEntryId().value());
629 localFlowEntry.setFlowEntryId(flowEntryId);
630 updated = true;
631 }
632
633 //
634 // Update the local Flow Entry, and keep state to check
635 // if the Flow Path has been installed.
636 //
637 if (localFlowEntry.flowEntryUserState() !=
638 newFlowEntry.flowEntryUserState()) {
639 localFlowEntry.setFlowEntryUserState(
640 newFlowEntry.flowEntryUserState());
641 updated = true;
642 }
643 if (localFlowEntry.flowEntrySwitchState() !=
644 newFlowEntry.flowEntrySwitchState()) {
645 localFlowEntry.setFlowEntrySwitchState(
646 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800647 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800648 updated = true;
649 }
650
651 return updated;
652 }
653
654 /**
655 * Find a Flow Entry that should be updated because of an external
656 * ENTRY_REMOVE event.
657 *
658 * @param flowPath the FlowPath for the Flow Entry to update.
659 * @param newFlowEntry the FlowEntry with the new state.
660 * @return the Flow Entry that should be updated if found, otherwise null.
661 */
662 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
663 FlowEntry newFlowEntry) {
664 //
665 // Iterate over all Flow Entries and find a match based on
666 // the Flow Entry ID.
667 //
668 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
669 if (! localFlowEntry.isValidFlowEntryId())
670 continue;
671 if (localFlowEntry.flowEntryId().value() !=
672 newFlowEntry.flowEntryId().value()) {
673 continue;
674 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800675 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700676 }
677
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800678 return null; // Entry not found
679 }
680
681 /**
682 * Update a Flow Entry because of an external ENTRY_REMOVE event.
683 *
684 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800685 * @param localFlowEntry the local Flow Entry to update.
686 * @param newFlowEntry the FlowEntry with the new state.
687 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800688 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800689 private boolean updateFlowEntryRemove(FlowPath flowPath,
690 FlowEntry localFlowEntry,
691 FlowEntry newFlowEntry) {
692 boolean updated = false;
693
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800694 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800695 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800696 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800697 if (localFlowEntry.flowEntryUserState() !=
698 newFlowEntry.flowEntryUserState()) {
699 localFlowEntry.setFlowEntryUserState(
700 newFlowEntry.flowEntryUserState());
701 updated = true;
702 }
703 if (localFlowEntry.flowEntrySwitchState() !=
704 newFlowEntry.flowEntrySwitchState()) {
705 localFlowEntry.setFlowEntrySwitchState(
706 newFlowEntry.flowEntrySwitchState());
707 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800708 }
709
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800710 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700711 }
712
713 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700714 * Recompute a Flow Path.
715 *
716 * @param flowPath the Flow Path to recompute.
717 * @return true if the recomputed Flow Path has changed, otherwise false.
718 */
719 private boolean recomputeFlowPath(FlowPath flowPath) {
720 boolean hasChanged = false;
721
722 //
723 // Test whether the Flow Path needs to be recomputed
724 //
725 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700726 case FP_TYPE_UNKNOWN:
727 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700728 case FP_TYPE_SHORTEST_PATH:
729 break;
730 case FP_TYPE_EXPLICIT_PATH:
731 return false; // An explicit path never changes
732 }
733
734 DataPath oldDataPath = flowPath.dataPath();
735
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700736 // Compute the new path
737 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
738 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700739 if (newDataPath == null) {
740 // We need the DataPath to compare the paths
741 newDataPath = new DataPath();
742 }
743 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
744
745 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700746 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700747 //
748 if (oldDataPath.flowEntries().size() !=
749 newDataPath.flowEntries().size()) {
750 hasChanged = true;
751 } else {
752 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
753 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
754 while (oldIter.hasNext() && newIter.hasNext()) {
755 FlowEntry oldFlowEntry = oldIter.next();
756 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700757 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
758 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700759 hasChanged = true;
760 break;
761 }
762 }
763 }
764 if (! hasChanged)
765 return hasChanged;
766
767 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700768 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700769 // - If a Flow Entry for a switch is in the old data path, but not
770 // in the new data path, then mark it for deletion.
771 // - If a Flow Entry for a switch is in the new data path, but not
772 // in the old data path, then mark it for addition.
773 // - If a Flow Entry for a switch is in both the old and the new
774 // data path, but it has changed, e.g., the incoming and/or outgoing
775 // port(s), then mark the old Flow Entry for deletion, and mark
776 // the new Flow Entry for addition.
777 // - If a Flow Entry for a switch is in both the old and the new
778 // data path, and it hasn't changed, then just keep it.
779 //
780 // NOTE: We use the Switch DPID of each entry to match the entries
781 //
782 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
783 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
784 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
785 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
786
787 // Prepare maps with the Flow Entries, so they are fast to lookup
788 for (FlowEntry flowEntry : oldDataPath.flowEntries())
789 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
790 for (FlowEntry flowEntry : newDataPath.flowEntries())
791 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
792
793 //
794 // Find the old Flow Entries that should be deleted
795 //
796 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
797 FlowEntry newFlowEntry =
798 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
799 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800800 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700801 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
802 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
803 deletedFlowEntries.add(oldFlowEntry);
804 }
805 }
806
807 //
808 // Find the new Flow Entries that should be added or updated
809 //
810 int idx = 0;
811 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
812 FlowEntry oldFlowEntry =
813 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
814
815 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700816 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
817 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700818 //
819 // Both Flow Entries are same
820 //
821 finalFlowEntries.add(oldFlowEntry);
822 idx++;
823 continue;
824 }
825
826 if (oldFlowEntry != null) {
827 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800828 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700829 //
830 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
831 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
832 deletedFlowEntries.add(oldFlowEntry);
833 }
834
835 //
836 // Add the new Flow Entry
837 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700838 //
839 // NOTE: Assign only the Flow ID.
840 // The Flow Entry ID is assigned later only for the Flow Entries
841 // this instance is responsible for.
842 //
843 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700844
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800845 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800846 // Copy the Flow timeouts
847 //
848 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
849 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
850
851 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800852 // Allocate the FlowEntryMatch by copying the default one
853 // from the FlowPath (if set).
854 //
855 FlowEntryMatch flowEntryMatch = null;
856 if (flowPath.flowEntryMatch() != null)
857 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
858 else
859 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700860 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800861
862 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700863 flowEntryMatch.enableInPort(newFlowEntry.inPort());
864
865 //
866 // Set the actions:
867 // If the first Flow Entry, copy the Flow Path actions to it.
868 //
869 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
870 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
871 FlowEntryActions flowActions =
872 new FlowEntryActions(flowPath.flowEntryActions());
873 for (FlowEntryAction action : flowActions.actions())
874 flowEntryActions.addAction(action);
875 }
876 idx++;
877
878 //
879 // Add the outgoing port output action
880 //
881 FlowEntryAction flowEntryAction = new FlowEntryAction();
882 flowEntryAction.setActionOutput(newFlowEntry.outPort());
883 flowEntryActions.addAction(flowEntryAction);
884
885 //
886 // Set the state of the new Flow Entry
887 //
888 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
889 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
890 finalFlowEntries.add(newFlowEntry);
891 }
892
893 //
894 // Replace the old Flow Entries with the new Flow Entries.
895 // Note that the Flow Entries that will be deleted are added at
896 // the end.
897 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800898 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700899 flowPath.dataPath().setFlowEntries(finalFlowEntries);
900
901 return hasChanged;
902 }
903
904 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700905 * Receive a notification that a Flow is added.
906 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700907 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700908 */
909 @Override
910 public void notificationRecvFlowAdded(FlowPath flowPath) {
911 EventEntry<FlowPath> eventEntry =
912 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
913 networkEvents.add(eventEntry);
914 }
915
916 /**
917 * Receive a notification that a Flow is removed.
918 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700919 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700920 */
921 @Override
922 public void notificationRecvFlowRemoved(FlowPath flowPath) {
923 EventEntry<FlowPath> eventEntry =
924 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
925 networkEvents.add(eventEntry);
926 }
927
928 /**
929 * Receive a notification that a Flow is updated.
930 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700931 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700932 */
933 @Override
934 public void notificationRecvFlowUpdated(FlowPath flowPath) {
935 // NOTE: The ADD and UPDATE events are processed in same way
936 EventEntry<FlowPath> eventEntry =
937 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
938 networkEvents.add(eventEntry);
939 }
940
941 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700942 * Receive a notification that a FlowEntry is added.
943 *
944 * @param flowEntry the FlowEntry that is added.
945 */
946 @Override
947 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
948 EventEntry<FlowEntry> eventEntry =
949 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
950 networkEvents.add(eventEntry);
951 }
952
953 /**
954 * Receive a notification that a FlowEntry is removed.
955 *
956 * @param flowEntry the FlowEntry that is removed.
957 */
958 @Override
959 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
960 EventEntry<FlowEntry> eventEntry =
961 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
962 networkEvents.add(eventEntry);
963 }
964
965 /**
966 * Receive a notification that a FlowEntry is updated.
967 *
968 * @param flowEntry the FlowEntry that is updated.
969 */
970 @Override
971 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
972 // NOTE: The ADD and UPDATE events are processed in same way
973 EventEntry<FlowEntry> eventEntry =
974 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
975 networkEvents.add(eventEntry);
976 }
977
978 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700979 * Receive a notification that a Topology Element is added.
980 *
981 * @param topologyElement the Topology Element that is added.
982 */
983 @Override
984 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
985 EventEntry<TopologyElement> eventEntry =
986 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
987 networkEvents.add(eventEntry);
988 }
989
990 /**
991 * Receive a notification that a Topology Element is removed.
992 *
993 * @param topologyElement the Topology Element that is removed.
994 */
995 @Override
996 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
997 EventEntry<TopologyElement> eventEntry =
998 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
999 networkEvents.add(eventEntry);
1000 }
1001
1002 /**
1003 * Receive a notification that a Topology Element is updated.
1004 *
1005 * @param topologyElement the Topology Element that is updated.
1006 */
1007 @Override
1008 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1009 // NOTE: The ADD and UPDATE events are processed in same way
1010 EventEntry<TopologyElement> eventEntry =
1011 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1012 networkEvents.add(eventEntry);
1013 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001014
1015 /**
1016 * Get a sorted copy of all Flow Paths.
1017 *
1018 * @return a sorted copy of all Flow Paths.
1019 */
1020 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1021 SortedMap<Long, FlowPath> sortedFlowPaths =
1022 new TreeMap<Long, FlowPath>();
1023
1024 //
1025 // TODO: For now we use serialization/deserialization to create
1026 // a copy of each Flow Path. In the future, we should use proper
1027 // copy constructors.
1028 //
1029 Kryo kryo = kryoFactory.newKryo();
1030 synchronized (allFlowPaths) {
1031 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1032 FlowPath origFlowPath = entry.getValue();
1033 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1034 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1035 }
1036 }
1037 kryoFactory.deleteKryo(kryo);
1038
1039 return sortedFlowPaths;
1040 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001041}