blob: d4b57f8fff46d2b78c8bbfc2664f6edaf3fd72ad [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;
Naoki Shiota0abe38d2014-01-07 15:31:22 -080017import net.onrc.onos.graph.GraphDBOperation;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070018import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070019import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070020import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070021import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080022import net.onrc.onos.ofcontroller.util.Dpid;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070023import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070024import net.onrc.onos.ofcontroller.util.FlowEntry;
25import net.onrc.onos.ofcontroller.util.FlowEntryAction;
26import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070027import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070028import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
29import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
30import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070031import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070032import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070033import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080034import net.onrc.onos.ofcontroller.util.Port;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080035import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
36
37import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070038
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070043 * Class for FlowPath Maintenance.
44 * This class listens for FlowEvents to:
45 * - Maintain a local cache of the Network Topology.
46 * - Detect FlowPaths impacted by Topology change.
47 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070048 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070049class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080050
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080051 private boolean enableOnrc2014MeasurementsFlows = true;
52 private boolean enableOnrc2014MeasurementsTopology = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080053
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070054 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070055 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Naoki Shiota0abe38d2014-01-07 15:31:22 -080056
Naoki Shiota0abe38d2014-01-07 15:31:22 -080057 private GraphDBOperation dbHandler;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070058 private FlowManager flowManager; // The Flow Manager to use
59 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070060 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080061 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070062
63 // The queue with Flow Path and Topology Element updates
64 private BlockingQueue<EventEntry<?>> networkEvents =
65 new LinkedBlockingQueue<EventEntry<?>>();
66
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070067 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070068 private List<EventEntry<TopologyElement>> topologyEvents =
69 new LinkedList<EventEntry<TopologyElement>>();
70 private List<EventEntry<FlowPath>> flowPathEvents =
71 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070072 private List<EventEntry<FlowEntry>> flowEntryEvents =
73 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -080074 private List<EventEntry<FlowId>> flowIdEvents =
75 new LinkedList<EventEntry<FlowId>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070076
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080077 // All internally computed Flow Paths
78 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
79
80 // The Flow Entries received as notifications with unmatched Flow Paths
81 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
82 new HashMap<Long, FlowEntry>();
83
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080084 //
85 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080086 // - The Flow Paths that should be recomputed
87 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080088 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080089 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080090 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
91 new HashMap<Long, FlowPath>();
92 private Map<Long, FlowPath> modifiedFlowPaths =
93 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080094 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
95 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080096
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070097 /**
98 * Constructor for a given Flow Manager and Datagrid Service.
99 *
100 * @param flowManager the Flow Manager to use.
101 * @param datagridService the Datagrid Service to use.
102 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700103 FlowEventHandler(FlowManager flowManager,
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800104 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700105 this.flowManager = flowManager;
106 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700107 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700108 }
109
110 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800111 * Get the network topology.
112 *
113 * @return the network topology.
114 */
115 protected Topology getTopology() { return this.topology; }
116
117 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800118 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700119 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800120 private void startup() {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800121 this.dbHandler = new GraphDBOperation("");
122
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700123 //
124 // Obtain the initial Topology state
125 //
126 Collection<TopologyElement> topologyElements =
127 datagridService.getAllTopologyElements();
128 for (TopologyElement topologyElement : topologyElements) {
129 EventEntry<TopologyElement> eventEntry =
130 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
131 topologyEvents.add(eventEntry);
132 }
133 //
134 // Obtain the initial Flow Path state
135 //
136 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
137 for (FlowPath flowPath : flowPaths) {
138 EventEntry<FlowPath> eventEntry =
139 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
140 flowPathEvents.add(eventEntry);
141 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700142 //
143 // Obtain the initial FlowEntry state
144 //
145 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
146 for (FlowEntry flowEntry : flowEntries) {
147 EventEntry<FlowEntry> eventEntry =
148 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
149 flowEntryEvents.add(eventEntry);
150 }
151
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800152 //
153 // Obtain the initial FlowId state
154 //
155 Collection<FlowId> flowIds = datagridService.getAllFlowIds();
156 for (FlowId flowId : flowIds) {
157 EventEntry<FlowId> eventEntry =
158 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
159 flowIdEvents.add(eventEntry);
160 }
161
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800162 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800163 synchronized (allFlowPaths) {
164 processEvents();
165 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800166 }
167
168 /**
169 * Run the thread.
170 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800171 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800172 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800173 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800174 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700175
176 //
177 // The main loop
178 //
179 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
180 try {
181 while (true) {
182 EventEntry<?> eventEntry = networkEvents.take();
183 collection.add(eventEntry);
184 networkEvents.drainTo(collection);
185
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700186 //
187 // Demultiplex all events:
188 // - EventEntry<TopologyElement>
189 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700190 // - EventEntry<FlowEntry>
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800191 // - EventEntry<FlowId>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700192 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700193 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800194 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700195 if (event.eventData() instanceof TopologyElement) {
196 EventEntry<TopologyElement> topologyEventEntry =
197 (EventEntry<TopologyElement>)event;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800198
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700199 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800200 continue;
201 }
202
203 // FlowPath event
204 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700205 EventEntry<FlowPath> flowPathEventEntry =
206 (EventEntry<FlowPath>)event;
207 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800208 continue;
209 }
210
211 // FlowEntry event
212 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700213 EventEntry<FlowEntry> flowEntryEventEntry =
214 (EventEntry<FlowEntry>)event;
215 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800216 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700217 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800218
219 // FlowId event
220 if (event.eventData() instanceof FlowId) {
221 EventEntry<FlowId> flowIdEventEntry =
222 (EventEntry<FlowId>)event;
223 flowIdEvents.add(flowIdEventEntry);
224 continue;
225 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700226 }
227 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700228
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700229 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800230 synchronized (allFlowPaths) {
231 processEvents();
232 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700233 }
234 } catch (Exception exception) {
235 log.debug("Exception processing Network Events: ", exception);
236 }
237 }
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800238
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700239 /**
240 * Process the events (if any)
241 */
242 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800243 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700244
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800245 if (enableOnrc2014MeasurementsFlows) {
246
247 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty()) {
248 return; // Nothing to do
249 }
250
251 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
252
253 // Fetch and prepare my flows
254 prepareMyFlows(mySwitches);
255
256 // Fetch the topology
257 processTopologyEvents();
258
259 // Recompute all affected Flow Paths and keep only the modified
260 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
261 if (recomputeFlowPath(flowPath))
262 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
263 }
264
265 // Assign the Flow Entry ID as needed
266 for (FlowPath flowPath : modifiedFlowPaths.values()) {
267 for (FlowEntry flowEntry : flowPath.flowEntries()) {
268 if (! flowEntry.isValidFlowEntryId()) {
269 long id = flowManager.getNextFlowEntryId();
270 flowEntry.setFlowEntryId(new FlowEntryId(id));
271 }
272 }
273 }
274
275 // Extract my modified Flow Entries
276 modifiedFlowEntries = processFlowIdEvents(mySwitches);
277
278 //
279 // Push the modified state to the Flow Manager
280 //
281 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
282 modifiedFlowEntries);
283
284 // Cleanup
285 topologyEvents.clear();
286 flowIdEvents.clear();
287 //
288 allFlowPaths.clear();
289 shouldRecomputeFlowPaths.clear();
290 modifiedFlowPaths.clear();
291
292 return;
293 }
294
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700295 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800296 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700297 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700298 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700299
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800300 processFlowPathEvents();
301 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800302 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800303 processFlowEntryEvents();
304
305 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800306 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800307 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800308 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800309 }
310
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800311 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800312 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800313
314 // Assign missing Flow Entry IDs
315 assignFlowEntryId(modifiedFlowEntries);
316
317 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800318 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800319 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800320 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
321 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800322
323 //
324 // Remove Flow Entries that were deleted
325 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800326 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800327 flowPath.dataPath().removeDeletedFlowEntries();
328
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800329 //
330 // Check if Flow Paths have been installed into all switches,
331 // and generate the appropriate events.
332 //
333 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
334
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800335 // Cleanup
336 topologyEvents.clear();
337 flowPathEvents.clear();
338 flowEntryEvents.clear();
339 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800340 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800341 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800342 checkIfInstalledFlowPaths.clear();
343 }
344
345 /**
346 * Check if Flow Paths have been installed into all switches,
347 * and generate the appropriate events.
348 *
349 * @param flowPaths the flowPaths to process.
350 */
351 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
352 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
353
354 Kryo kryo = kryoFactory.newKryo();
355
356 for (FlowPath flowPath : flowPaths) {
357 boolean isInstalled = true;
358
359 //
360 // Check whether all Flow Entries have been installed
361 //
362 for (FlowEntry flowEntry : flowPath.flowEntries()) {
363 if (flowEntry.flowEntrySwitchState() !=
364 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
365 isInstalled = false;
366 break;
367 }
368 }
369
370 if (isInstalled) {
371 // Create a copy and add it to the list
372 FlowPath copyFlowPath = kryo.copy(flowPath);
373 installedFlowPaths.add(copyFlowPath);
374 }
375 }
376 kryoFactory.deleteKryo(kryo);
377
378 // Generate an event for the installed Flow Path.
379 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800380 }
381
382 /**
383 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800384 *
385 * @param modifiedFlowPaths the Flow Paths to process.
386 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800387 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800388 private Collection<FlowEntry> extractModifiedFlowEntries(
389 Collection<FlowPath> modifiedFlowPaths) {
390 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800391
392 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800393 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800394 for (FlowEntry flowEntry : flowPath.flowEntries()) {
395 if (flowEntry.flowEntrySwitchState() ==
396 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800397 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800398 }
399 }
400 }
401 return modifiedFlowEntries;
402 }
403
404 /**
405 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800406 *
407 * @param modifiedFlowEnries the collection of Flow Entries that need
408 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800409 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800410 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800411 if (modifiedFlowEntries.isEmpty())
412 return;
413
414 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
415
416 //
417 // Assign the Flow Entry ID only for Flow Entries for my switches
418 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800419 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800420 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
421 if (mySwitch == null)
422 continue;
423 if (! flowEntry.isValidFlowEntryId()) {
424 long id = flowManager.getNextFlowEntryId();
425 flowEntry.setFlowEntryId(new FlowEntryId(id));
426 }
427 }
428 }
429
430 /**
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800431 * Prepare my flows.
432 *
433 * @param mySwitches the collection of my switches.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800434 */
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800435 private void prepareMyFlows(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800436 if (! topologyEvents.isEmpty()) {
437 // Fetch my flows from the database
438 ArrayList<FlowPath> myFlows = FlowDatabaseOperation.getAllMyFlows(dbHandler, mySwitches);
439 for (FlowPath flowPath : myFlows) {
440 allFlowPaths.put(flowPath.flowId().value(), flowPath);
441
442 //
443 // TODO: Bug workaround / fix :
444 // method FlowDatabaseOperation.extractFlowEntry() doesn't
445 // fetch the inPort and outPort, hence we assign them here.
446 //
447 // Assign the inPort and outPort for the Flow Entries
448 for (FlowEntry flowEntry : flowPath.flowEntries()) {
449 // Set the inPort
450 do {
451 if (flowEntry.inPort() != null)
452 break;
453 if (flowEntry.flowEntryMatch() == null)
454 break;
455 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
456 flowEntry.setInPort(inPort);
457 } while (false);
458
459 // Set the outPort
460 do {
461 if (flowEntry.outPort() != null)
462 break;
463 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
464 if (fa.actionOutput() != null) {
465 Port outPort = new Port(fa.actionOutput().port().value());
466 flowEntry.setOutPort(outPort);
467 break;
468 }
469 }
470 } while (false);
471 }
472 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800473 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800474
475 //
476 // Automatically add all Flow ID events (for the Flows this instance
477 // is responsible for) to the collection of Flows to recompute.
478 //
479 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
480 FlowId flowId = eventEntry.eventData();
481 FlowPath flowPath = allFlowPaths.get(flowId.value());
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800482 if (flowPath == null) {
483 if (! topologyEvents.isEmpty())
484 continue; // Optimization: Not my flow
485 Dpid dpid = FlowDatabaseOperation.getFlowSourceDpid(dbHandler,
486 flowId);
487 if ((dpid != null) && (mySwitches.get(dpid.value()) != null)) {
488 flowPath = FlowDatabaseOperation.getFlow(dbHandler,
489 flowId);
490 }
491 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800492 if (flowPath != null) {
493 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
494 flowPath);
495 }
496 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800497 }
498
499 /**
500 * Process the Flow ID events.
501 *
502 * @param mySwitches the collection of my switches.
503 * @return a collection of modified Flow Entries this instance needs
504 * to push to its own switches.
505 */
506 private Collection<FlowEntry> processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
507 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
508
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800509 //
510 // Process all Flow ID events and update the appropriate state
511 //
512 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
513 FlowId flowId = eventEntry.eventData();
514
515 log.debug("Flow ID Event: {} {}", eventEntry.eventType(), flowId);
516
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800517 //
518 // Lookup the Flow ID in the Flows that were read from the
519 // database in in a previous step. If not found, read from
520 // the database.
521 //
522 FlowPath flowPath = allFlowPaths.get(flowId.value());
523 if (flowPath == null)
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800524 flowPath = FlowDatabaseOperation.getFlow(dbHandler, flowId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800525 if (flowPath == null) {
526 log.debug("Flow ID {} : Flow not found!", flowId);
527 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800528 }
529
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800530 // Collect only my flow entries that are not updated.
531 for (FlowEntry flowEntry : flowPath.flowEntries()) {
532 if (flowEntry.flowEntrySwitchState() !=
533 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
534 continue;
535 }
536 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
537 if (mySwitch == null)
538 continue;
539 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800540 }
541 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800542
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800543 return modifiedFlowEntries;
544 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800545
546 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800547 * Process the Flow Path events.
548 */
549 private void processFlowPathEvents() {
550 //
551 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700552 //
553 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
554 FlowPath flowPath = eventEntry.eventData();
555
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800556 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800557
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700558 switch (eventEntry.eventType()) {
559 case ENTRY_ADD: {
560 //
561 // Add a new Flow Path
562 //
563 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
564 //
565 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800566 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700567 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700568 }
569
570 switch (flowPath.flowPathType()) {
571 case FP_TYPE_SHORTEST_PATH:
572 //
573 // Reset the Data Path, in case it was set already, because
574 // we are going to recompute it anyway.
575 //
576 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800577 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
578 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700579 break;
580 case FP_TYPE_EXPLICIT_PATH:
581 //
582 // Mark all Flow Entries for installation in the switches.
583 //
584 for (FlowEntry flowEntry : flowPath.flowEntries()) {
585 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
586 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800587 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700588 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800589 case FP_TYPE_UNKNOWN:
590 log.error("FlowPath event with unknown type");
591 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700592 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800593 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700594
595 break;
596 }
597
598 case ENTRY_REMOVE: {
599 //
600 // Remove an existing Flow Path.
601 //
602 // Find the Flow Path, and mark the Flow and its Flow Entries
603 // for deletion.
604 //
605 FlowPath existingFlowPath =
606 allFlowPaths.get(flowPath.flowId().value());
607 if (existingFlowPath == null)
608 continue; // Nothing to do
609
610 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
611 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
612 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
613 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
614 }
615
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800616 // Remove the Flow Path from the internal state
617 Long key = existingFlowPath.flowId().value();
618 allFlowPaths.remove(key);
619 shouldRecomputeFlowPaths.remove(key);
620 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700621
622 break;
623 }
624 }
625 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800626 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700627
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800628 /**
629 * Process the Topology events.
630 */
631 private void processTopologyEvents() {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800632 if (enableOnrc2014MeasurementsTopology) {
633 if (topologyEvents.isEmpty())
634 return;
635 log.debug("[BEFORE] {}", topology.toString());
636 topology.readFromDatabase(dbHandler);
637 log.debug("[AFTER] {}", topology.toString());
638 shouldRecomputeFlowPaths.putAll(allFlowPaths);
639 return;
640 }
641
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700642 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800643 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700644 //
645 boolean isTopologyModified = false;
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800646 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
647 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800648
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800649 log.debug("Topology Event: {} {}", eventEntry.eventType(),
650 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800651
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800652 switch (eventEntry.eventType()) {
653 case ENTRY_ADD:
654 isTopologyModified |= topology.addTopologyElement(topologyElement);
655 break;
656 case ENTRY_REMOVE:
657 isTopologyModified |= topology.removeTopologyElement(topologyElement);
658 break;
659 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700660 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700661 if (isTopologyModified) {
662 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800663 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700664 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800665 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700666
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800667 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800668 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800669 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800670 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800671 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800672 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800673
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700674 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800675 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700676 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800677 if (! unmatchedFlowEntryAdd.isEmpty()) {
678 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
679 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800680 // log.debug("Processing Unmatched Flow Entry: {}",
681 // flowEntry.toString());
682
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800683 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800684 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800685 remainingUpdates.put(flowEntry.flowEntryId().value(),
686 flowEntry);
687 continue;
688 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800689 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
690 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800691 remainingUpdates.put(flowEntry.flowEntryId().value(),
692 flowEntry);
693 continue;
694 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800695 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
696 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
697 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700698 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800699 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700700 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800701 }
702
703 /**
704 * Process the Flow Entry events.
705 */
706 private void processFlowEntryEvents() {
707 FlowPath flowPath;
708 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700709
710 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800711 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700712 //
713 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
714 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800715
716 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800717 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800718
719 if ((! flowEntry.isValidFlowId()) ||
720 (! flowEntry.isValidFlowEntryId())) {
721 continue;
722 }
723
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700724 switch (eventEntry.eventType()) {
725 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800726 flowPath = allFlowPaths.get(flowEntry.flowId().value());
727 if (flowPath == null) {
728 // Flow Path not found: keep the entry for later matching
729 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
730 flowEntry);
731 break;
732 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800733 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
734 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800735 // Flow Entry not found: keep the entry for later matching
736 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
737 flowEntry);
738 break;
739 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800740 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
741 // Add the updated Flow Path to the list of updated paths
742 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
743 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700744 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800745
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700746 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800747 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
748 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800749 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800750 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800751
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800752 flowPath = allFlowPaths.get(flowEntry.flowId().value());
753 if (flowPath == null) {
754 // Flow Path not found: ignore the update
755 break;
756 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800757 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
758 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800759 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800760 break;
761 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800762 if (updateFlowEntryRemove(flowPath, localFlowEntry,
763 flowEntry)) {
764 // Add the updated Flow Path to the list of updated paths
765 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
766 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700767 break;
768 }
769 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700770 }
771
772 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800773 * Find a Flow Entry that should be updated because of an external
774 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700775 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800776 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800777 * @param newFlowEntry the FlowEntry with the new state.
778 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700779 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800780 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
781 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700782 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800783 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700784 //
785 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800786 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800787 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700788 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800789 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700790
791 //
792 // Local Flow Entry match found
793 //
794 if (localFlowEntry.isValidFlowEntryId()) {
795 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800796 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700797 //
798 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800799 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700800 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800801 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700802 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700803 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800804 return localFlowEntry;
805 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700806
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800807 return null; // Entry not found
808 }
809
810 /**
811 * Update a Flow Entry because of an external ENTRY_ADD event.
812 *
813 * @param flowPath the FlowPath for the Flow Entry to update.
814 * @param localFlowEntry the local Flow Entry to update.
815 * @param newFlowEntry the FlowEntry with the new state.
816 * @return true if the local Flow Entry was updated, otherwise false.
817 */
818 private boolean updateFlowEntryAdd(FlowPath flowPath,
819 FlowEntry localFlowEntry,
820 FlowEntry newFlowEntry) {
821 boolean updated = false;
822
823 if (localFlowEntry.flowEntryUserState() ==
824 FlowEntryUserState.FE_USER_DELETE) {
825 // Don't add-back a Flow Entry that is already deleted
826 return false;
827 }
828
829 if (! localFlowEntry.isValidFlowEntryId()) {
830 // Update the Flow Entry ID
831 FlowEntryId flowEntryId =
832 new FlowEntryId(newFlowEntry.flowEntryId().value());
833 localFlowEntry.setFlowEntryId(flowEntryId);
834 updated = true;
835 }
836
837 //
838 // Update the local Flow Entry, and keep state to check
839 // if the Flow Path has been installed.
840 //
841 if (localFlowEntry.flowEntryUserState() !=
842 newFlowEntry.flowEntryUserState()) {
843 localFlowEntry.setFlowEntryUserState(
844 newFlowEntry.flowEntryUserState());
845 updated = true;
846 }
847 if (localFlowEntry.flowEntrySwitchState() !=
848 newFlowEntry.flowEntrySwitchState()) {
849 localFlowEntry.setFlowEntrySwitchState(
850 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800851 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800852 updated = true;
853 }
854
855 return updated;
856 }
857
858 /**
859 * Find a Flow Entry that should be updated because of an external
860 * ENTRY_REMOVE event.
861 *
862 * @param flowPath the FlowPath for the Flow Entry to update.
863 * @param newFlowEntry the FlowEntry with the new state.
864 * @return the Flow Entry that should be updated if found, otherwise null.
865 */
866 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
867 FlowEntry newFlowEntry) {
868 //
869 // Iterate over all Flow Entries and find a match based on
870 // the Flow Entry ID.
871 //
872 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
873 if (! localFlowEntry.isValidFlowEntryId())
874 continue;
875 if (localFlowEntry.flowEntryId().value() !=
876 newFlowEntry.flowEntryId().value()) {
877 continue;
878 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800879 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700880 }
881
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800882 return null; // Entry not found
883 }
884
885 /**
886 * Update a Flow Entry because of an external ENTRY_REMOVE event.
887 *
888 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800889 * @param localFlowEntry the local Flow Entry to update.
890 * @param newFlowEntry the FlowEntry with the new state.
891 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800892 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800893 private boolean updateFlowEntryRemove(FlowPath flowPath,
894 FlowEntry localFlowEntry,
895 FlowEntry newFlowEntry) {
896 boolean updated = false;
897
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800898 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800899 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800900 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800901 if (localFlowEntry.flowEntryUserState() !=
902 newFlowEntry.flowEntryUserState()) {
903 localFlowEntry.setFlowEntryUserState(
904 newFlowEntry.flowEntryUserState());
905 updated = true;
906 }
907 if (localFlowEntry.flowEntrySwitchState() !=
908 newFlowEntry.flowEntrySwitchState()) {
909 localFlowEntry.setFlowEntrySwitchState(
910 newFlowEntry.flowEntrySwitchState());
911 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800912 }
913
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800914 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700915 }
916
917 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700918 * Recompute a Flow Path.
919 *
920 * @param flowPath the Flow Path to recompute.
921 * @return true if the recomputed Flow Path has changed, otherwise false.
922 */
923 private boolean recomputeFlowPath(FlowPath flowPath) {
924 boolean hasChanged = false;
925
926 //
927 // Test whether the Flow Path needs to be recomputed
928 //
929 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700930 case FP_TYPE_UNKNOWN:
931 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700932 case FP_TYPE_SHORTEST_PATH:
933 break;
934 case FP_TYPE_EXPLICIT_PATH:
935 return false; // An explicit path never changes
936 }
937
938 DataPath oldDataPath = flowPath.dataPath();
939
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700940 // Compute the new path
941 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
942 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700943 if (newDataPath == null) {
944 // We need the DataPath to compare the paths
945 newDataPath = new DataPath();
946 }
947 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
948
949 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700950 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700951 //
952 if (oldDataPath.flowEntries().size() !=
953 newDataPath.flowEntries().size()) {
954 hasChanged = true;
955 } else {
956 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
957 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
958 while (oldIter.hasNext() && newIter.hasNext()) {
959 FlowEntry oldFlowEntry = oldIter.next();
960 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700961 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
962 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700963 hasChanged = true;
964 break;
965 }
966 }
967 }
968 if (! hasChanged)
969 return hasChanged;
970
971 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700972 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700973 // - If a Flow Entry for a switch is in the old data path, but not
974 // in the new data path, then mark it for deletion.
975 // - If a Flow Entry for a switch is in the new data path, but not
976 // in the old data path, then mark it for addition.
977 // - If a Flow Entry for a switch is in both the old and the new
978 // data path, but it has changed, e.g., the incoming and/or outgoing
979 // port(s), then mark the old Flow Entry for deletion, and mark
980 // the new Flow Entry for addition.
981 // - If a Flow Entry for a switch is in both the old and the new
982 // data path, and it hasn't changed, then just keep it.
983 //
984 // NOTE: We use the Switch DPID of each entry to match the entries
985 //
986 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
987 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
988 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
989 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
990
991 // Prepare maps with the Flow Entries, so they are fast to lookup
992 for (FlowEntry flowEntry : oldDataPath.flowEntries())
993 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
994 for (FlowEntry flowEntry : newDataPath.flowEntries())
995 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
996
997 //
998 // Find the old Flow Entries that should be deleted
999 //
1000 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1001 FlowEntry newFlowEntry =
1002 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1003 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001004 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001005 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1006 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1007 deletedFlowEntries.add(oldFlowEntry);
1008 }
1009 }
1010
1011 //
1012 // Find the new Flow Entries that should be added or updated
1013 //
1014 int idx = 0;
1015 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1016 FlowEntry oldFlowEntry =
1017 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1018
1019 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001020 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1021 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001022 //
1023 // Both Flow Entries are same
1024 //
1025 finalFlowEntries.add(oldFlowEntry);
1026 idx++;
1027 continue;
1028 }
1029
1030 if (oldFlowEntry != null) {
1031 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001032 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001033 //
1034 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1035 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1036 deletedFlowEntries.add(oldFlowEntry);
1037 }
1038
1039 //
1040 // Add the new Flow Entry
1041 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001042 //
1043 // NOTE: Assign only the Flow ID.
1044 // The Flow Entry ID is assigned later only for the Flow Entries
1045 // this instance is responsible for.
1046 //
1047 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001048
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001049 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001050 // Copy the Flow timeouts
1051 //
1052 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1053 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1054
1055 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001056 // Allocate the FlowEntryMatch by copying the default one
1057 // from the FlowPath (if set).
1058 //
1059 FlowEntryMatch flowEntryMatch = null;
1060 if (flowPath.flowEntryMatch() != null)
1061 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1062 else
1063 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001064 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001065
1066 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001067 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1068
1069 //
1070 // Set the actions:
1071 // If the first Flow Entry, copy the Flow Path actions to it.
1072 //
1073 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1074 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1075 FlowEntryActions flowActions =
1076 new FlowEntryActions(flowPath.flowEntryActions());
1077 for (FlowEntryAction action : flowActions.actions())
1078 flowEntryActions.addAction(action);
1079 }
1080 idx++;
1081
1082 //
1083 // Add the outgoing port output action
1084 //
1085 FlowEntryAction flowEntryAction = new FlowEntryAction();
1086 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1087 flowEntryActions.addAction(flowEntryAction);
1088
1089 //
1090 // Set the state of the new Flow Entry
1091 //
1092 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1093 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1094 finalFlowEntries.add(newFlowEntry);
1095 }
1096
1097 //
1098 // Replace the old Flow Entries with the new Flow Entries.
1099 // Note that the Flow Entries that will be deleted are added at
1100 // the end.
1101 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001102 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001103 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1104
1105 return hasChanged;
1106 }
1107
1108 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001109 * Receive a notification that a Flow is added.
1110 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001111 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001112 */
1113 @Override
1114 public void notificationRecvFlowAdded(FlowPath flowPath) {
1115 EventEntry<FlowPath> eventEntry =
1116 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1117 networkEvents.add(eventEntry);
1118 }
1119
1120 /**
1121 * Receive a notification that a Flow is removed.
1122 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001123 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001124 */
1125 @Override
1126 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1127 EventEntry<FlowPath> eventEntry =
1128 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1129 networkEvents.add(eventEntry);
1130 }
1131
1132 /**
1133 * Receive a notification that a Flow is updated.
1134 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001135 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001136 */
1137 @Override
1138 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1139 // NOTE: The ADD and UPDATE events are processed in same way
1140 EventEntry<FlowPath> eventEntry =
1141 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1142 networkEvents.add(eventEntry);
1143 }
1144
1145 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001146 * Receive a notification that a FlowEntry is added.
1147 *
1148 * @param flowEntry the FlowEntry that is added.
1149 */
1150 @Override
1151 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
1152 EventEntry<FlowEntry> eventEntry =
1153 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1154 networkEvents.add(eventEntry);
1155 }
1156
1157 /**
1158 * Receive a notification that a FlowEntry is removed.
1159 *
1160 * @param flowEntry the FlowEntry that is removed.
1161 */
1162 @Override
1163 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
1164 EventEntry<FlowEntry> eventEntry =
1165 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1166 networkEvents.add(eventEntry);
1167 }
1168
1169 /**
1170 * Receive a notification that a FlowEntry is updated.
1171 *
1172 * @param flowEntry the FlowEntry that is updated.
1173 */
1174 @Override
1175 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1176 // NOTE: The ADD and UPDATE events are processed in same way
1177 EventEntry<FlowEntry> eventEntry =
1178 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1179 networkEvents.add(eventEntry);
1180 }
1181
1182 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001183 * Receive a notification that a FlowId is added.
1184 *
1185 * @param flowId the FlowId that is added.
1186 */
1187 @Override
1188 public void notificationRecvFlowIdAdded(FlowId flowId) {
1189 EventEntry<FlowId> eventEntry =
1190 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1191 networkEvents.add(eventEntry);
1192 }
1193
1194 /**
1195 * Receive a notification that a FlowId is removed.
1196 *
1197 * @param flowId the FlowId that is removed.
1198 */
1199 @Override
1200 public void notificationRecvFlowIdRemoved(FlowId flowId) {
1201 EventEntry<FlowId> eventEntry =
1202 new EventEntry<FlowId>(EventEntry.Type.ENTRY_REMOVE, flowId);
1203 networkEvents.add(eventEntry);
1204 }
1205
1206 /**
1207 * Receive a notification that a FlowId is updated.
1208 *
1209 * @param flowId the FlowId that is updated.
1210 */
1211 @Override
1212 public void notificationRecvFlowIdUpdated(FlowId flowId) {
1213 // NOTE: The ADD and UPDATE events are processed in same way
1214 EventEntry<FlowId> eventEntry =
1215 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1216 networkEvents.add(eventEntry);
1217 }
1218
1219 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001220 * Receive a notification that a FlowEntryId is added.
1221 *
1222 * @param flowEntryId the FlowEntryId that is added.
1223 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1224 */
1225 @Override
1226 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1227 Dpid dpid) {
1228 // TODO: Implement it!
1229 /*
1230 EventEntry<FlowEntryId> eventEntry =
1231 new EventEntry<FlowEntryId>(EventEntry.Type.ENTRY_ADD, flowEntryId);
1232 networkEvents.add(eventEntry);
1233 */
1234 }
1235
1236 /**
1237 * Receive a notification that a FlowEntryId is removed.
1238 *
1239 * @param flowEntryId the FlowEntryId that is removed.
1240 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1241 */
1242 @Override
1243 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1244 Dpid dpid) {
1245 // TODO: Implement it!
1246 /*
1247 EventEntry<FlowEntryId> eventEntry =
1248 new EventEntry<FlowEntryId>(EventEntry.Type.ENTRY_REMOVE, flowEntryId);
1249 networkEvents.add(eventEntry);
1250 */
1251 }
1252
1253 /**
1254 * Receive a notification that a FlowEntryId is updated.
1255 *
1256 * @param flowEntryId the FlowEntryId that is updated.
1257 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1258 */
1259 @Override
1260 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1261 Dpid dpid) {
1262 // TODO: Implement it!
1263 /*
1264 // NOTE: The ADD and UPDATE events are processed in same way
1265 EventEntry<FlowEntryId> eventEntry =
1266 new EventEntry<FlowEntryId>(EventEntry.Type.ENTRY_ADD, flowEntryId);
1267 networkEvents.add(eventEntry);
1268 */
1269 }
1270
1271 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001272 * Receive a notification that a Topology Element is added.
1273 *
1274 * @param topologyElement the Topology Element that is added.
1275 */
1276 @Override
1277 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1278 EventEntry<TopologyElement> eventEntry =
1279 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1280 networkEvents.add(eventEntry);
1281 }
1282
1283 /**
1284 * Receive a notification that a Topology Element is removed.
1285 *
1286 * @param topologyElement the Topology Element that is removed.
1287 */
1288 @Override
1289 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1290 EventEntry<TopologyElement> eventEntry =
1291 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1292 networkEvents.add(eventEntry);
1293 }
1294
1295 /**
1296 * Receive a notification that a Topology Element is updated.
1297 *
1298 * @param topologyElement the Topology Element that is updated.
1299 */
1300 @Override
1301 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1302 // NOTE: The ADD and UPDATE events are processed in same way
1303 EventEntry<TopologyElement> eventEntry =
1304 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1305 networkEvents.add(eventEntry);
1306 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001307
1308 /**
1309 * Get a sorted copy of all Flow Paths.
1310 *
1311 * @return a sorted copy of all Flow Paths.
1312 */
1313 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1314 SortedMap<Long, FlowPath> sortedFlowPaths =
1315 new TreeMap<Long, FlowPath>();
1316
1317 //
1318 // TODO: For now we use serialization/deserialization to create
1319 // a copy of each Flow Path. In the future, we should use proper
1320 // copy constructors.
1321 //
1322 Kryo kryo = kryoFactory.newKryo();
1323 synchronized (allFlowPaths) {
1324 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1325 FlowPath origFlowPath = entry.getValue();
1326 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1327 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1328 }
1329 }
1330 kryoFactory.deleteKryo(kryo);
1331
1332 return sortedFlowPaths;
1333 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001334}