blob: 1f2cdf141fa1a670e00945fa93453e4161cf125f [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 Radoslavov6b79f2b2013-10-26 21:31:10 -070022import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070023import net.onrc.onos.ofcontroller.util.FlowEntry;
24import net.onrc.onos.ofcontroller.util.FlowEntryAction;
25import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070026import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070027import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
28import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
29import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070030import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070031import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070032import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080033import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
34
35import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070036
37import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
40/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070041 * Class for FlowPath Maintenance.
42 * This class listens for FlowEvents to:
43 * - Maintain a local cache of the Network Topology.
44 * - Detect FlowPaths impacted by Topology change.
45 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070046 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070047class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080048
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080049 private boolean enableOnrc2014MeasurementsFlows = true;
50 private boolean enableOnrc2014MeasurementsTopology = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080051
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070052 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070053 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Naoki Shiota0abe38d2014-01-07 15:31:22 -080054
Naoki Shiota0abe38d2014-01-07 15:31:22 -080055 private GraphDBOperation dbHandler;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070056 private FlowManager flowManager; // The Flow Manager to use
57 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070058 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080059 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070060
61 // The queue with Flow Path and Topology Element updates
62 private BlockingQueue<EventEntry<?>> networkEvents =
63 new LinkedBlockingQueue<EventEntry<?>>();
64
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070065 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070066 private List<EventEntry<TopologyElement>> topologyEvents =
67 new LinkedList<EventEntry<TopologyElement>>();
68 private List<EventEntry<FlowPath>> flowPathEvents =
69 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070070 private List<EventEntry<FlowEntry>> flowEntryEvents =
71 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -080072 private List<EventEntry<FlowId>> flowIdEvents =
73 new LinkedList<EventEntry<FlowId>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070074
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080075 // All internally computed Flow Paths
76 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
77
78 // The Flow Entries received as notifications with unmatched Flow Paths
79 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
80 new HashMap<Long, FlowEntry>();
81
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080082 //
83 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080084 // - The Flow Paths that should be recomputed
85 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080086 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080087 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080088 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
89 new HashMap<Long, FlowPath>();
90 private Map<Long, FlowPath> modifiedFlowPaths =
91 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080092 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
93 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080094
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070095 /**
96 * Constructor for a given Flow Manager and Datagrid Service.
97 *
98 * @param flowManager the Flow Manager to use.
99 * @param datagridService the Datagrid Service to use.
100 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700101 FlowEventHandler(FlowManager flowManager,
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800102 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700103 this.flowManager = flowManager;
104 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700105 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700106 }
107
108 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800109 * Get the network topology.
110 *
111 * @return the network topology.
112 */
113 protected Topology getTopology() { return this.topology; }
114
115 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800116 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700117 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800118 private void startup() {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800119 this.dbHandler = new GraphDBOperation("");
120
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700121 //
122 // Obtain the initial Topology state
123 //
124 Collection<TopologyElement> topologyElements =
125 datagridService.getAllTopologyElements();
126 for (TopologyElement topologyElement : topologyElements) {
127 EventEntry<TopologyElement> eventEntry =
128 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
129 topologyEvents.add(eventEntry);
130 }
131 //
132 // Obtain the initial Flow Path state
133 //
134 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
135 for (FlowPath flowPath : flowPaths) {
136 EventEntry<FlowPath> eventEntry =
137 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
138 flowPathEvents.add(eventEntry);
139 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700140 //
141 // Obtain the initial FlowEntry state
142 //
143 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
144 for (FlowEntry flowEntry : flowEntries) {
145 EventEntry<FlowEntry> eventEntry =
146 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
147 flowEntryEvents.add(eventEntry);
148 }
149
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800150 //
151 // Obtain the initial FlowId state
152 //
153 Collection<FlowId> flowIds = datagridService.getAllFlowIds();
154 for (FlowId flowId : flowIds) {
155 EventEntry<FlowId> eventEntry =
156 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
157 flowIdEvents.add(eventEntry);
158 }
159
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800160 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800161 synchronized (allFlowPaths) {
162 processEvents();
163 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800164 }
165
166 /**
167 * Run the thread.
168 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800169 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800170 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800171 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800172 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700173
174 //
175 // The main loop
176 //
177 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
178 try {
179 while (true) {
180 EventEntry<?> eventEntry = networkEvents.take();
181 collection.add(eventEntry);
182 networkEvents.drainTo(collection);
183
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700184 //
185 // Demultiplex all events:
186 // - EventEntry<TopologyElement>
187 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700188 // - EventEntry<FlowEntry>
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800189 // - EventEntry<FlowId>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700190 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700191 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800192 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700193 if (event.eventData() instanceof TopologyElement) {
194 EventEntry<TopologyElement> topologyEventEntry =
195 (EventEntry<TopologyElement>)event;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800196
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700197 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800198 continue;
199 }
200
201 // FlowPath event
202 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700203 EventEntry<FlowPath> flowPathEventEntry =
204 (EventEntry<FlowPath>)event;
205 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800206 continue;
207 }
208
209 // FlowEntry event
210 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700211 EventEntry<FlowEntry> flowEntryEventEntry =
212 (EventEntry<FlowEntry>)event;
213 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800214 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700215 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800216
217 // FlowId event
218 if (event.eventData() instanceof FlowId) {
219 EventEntry<FlowId> flowIdEventEntry =
220 (EventEntry<FlowId>)event;
221 flowIdEvents.add(flowIdEventEntry);
222 continue;
223 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700224 }
225 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700226
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700227 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800228 synchronized (allFlowPaths) {
229 processEvents();
230 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700231 }
232 } catch (Exception exception) {
233 log.debug("Exception processing Network Events: ", exception);
234 }
235 }
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800236
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700237 /**
238 * Process the events (if any)
239 */
240 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800241 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700242
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800243 if (enableOnrc2014MeasurementsFlows) {
244
245 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty()) {
246 return; // Nothing to do
247 }
248
249 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
250
251 // Fetch and prepare my flows
252 prepareMyFlows(mySwitches);
253
254 // Fetch the topology
255 processTopologyEvents();
256
257 // Recompute all affected Flow Paths and keep only the modified
258 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
259 if (recomputeFlowPath(flowPath))
260 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
261 }
262
263 // Assign the Flow Entry ID as needed
264 for (FlowPath flowPath : modifiedFlowPaths.values()) {
265 for (FlowEntry flowEntry : flowPath.flowEntries()) {
266 if (! flowEntry.isValidFlowEntryId()) {
267 long id = flowManager.getNextFlowEntryId();
268 flowEntry.setFlowEntryId(new FlowEntryId(id));
269 }
270 }
271 }
272
273 // Extract my modified Flow Entries
274 modifiedFlowEntries = processFlowIdEvents(mySwitches);
275
276 //
277 // Push the modified state to the Flow Manager
278 //
279 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
280 modifiedFlowEntries);
281
282 // Cleanup
283 topologyEvents.clear();
284 flowIdEvents.clear();
285 //
286 allFlowPaths.clear();
287 shouldRecomputeFlowPaths.clear();
288 modifiedFlowPaths.clear();
289
290 return;
291 }
292
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700293 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800294 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700295 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700296 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700297
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800298 processFlowPathEvents();
299 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800300 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800301 processFlowEntryEvents();
302
303 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800304 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800305 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800306 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800307 }
308
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800309 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800310 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800311
312 // Assign missing Flow Entry IDs
313 assignFlowEntryId(modifiedFlowEntries);
314
315 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800316 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800317 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800318 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
319 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800320
321 //
322 // Remove Flow Entries that were deleted
323 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800324 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800325 flowPath.dataPath().removeDeletedFlowEntries();
326
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800327 //
328 // Check if Flow Paths have been installed into all switches,
329 // and generate the appropriate events.
330 //
331 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
332
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800333 // Cleanup
334 topologyEvents.clear();
335 flowPathEvents.clear();
336 flowEntryEvents.clear();
337 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800338 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800339 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800340 checkIfInstalledFlowPaths.clear();
341 }
342
343 /**
344 * Check if Flow Paths have been installed into all switches,
345 * and generate the appropriate events.
346 *
347 * @param flowPaths the flowPaths to process.
348 */
349 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
350 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
351
352 Kryo kryo = kryoFactory.newKryo();
353
354 for (FlowPath flowPath : flowPaths) {
355 boolean isInstalled = true;
356
357 //
358 // Check whether all Flow Entries have been installed
359 //
360 for (FlowEntry flowEntry : flowPath.flowEntries()) {
361 if (flowEntry.flowEntrySwitchState() !=
362 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
363 isInstalled = false;
364 break;
365 }
366 }
367
368 if (isInstalled) {
369 // Create a copy and add it to the list
370 FlowPath copyFlowPath = kryo.copy(flowPath);
371 installedFlowPaths.add(copyFlowPath);
372 }
373 }
374 kryoFactory.deleteKryo(kryo);
375
376 // Generate an event for the installed Flow Path.
377 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800378 }
379
380 /**
381 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800382 *
383 * @param modifiedFlowPaths the Flow Paths to process.
384 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800385 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800386 private Collection<FlowEntry> extractModifiedFlowEntries(
387 Collection<FlowPath> modifiedFlowPaths) {
388 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800389
390 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800391 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800392 for (FlowEntry flowEntry : flowPath.flowEntries()) {
393 if (flowEntry.flowEntrySwitchState() ==
394 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800395 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800396 }
397 }
398 }
399 return modifiedFlowEntries;
400 }
401
402 /**
403 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800404 *
405 * @param modifiedFlowEnries the collection of Flow Entries that need
406 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800407 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800408 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800409 if (modifiedFlowEntries.isEmpty())
410 return;
411
412 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
413
414 //
415 // Assign the Flow Entry ID only for Flow Entries for my switches
416 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800417 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800418 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
419 if (mySwitch == null)
420 continue;
421 if (! flowEntry.isValidFlowEntryId()) {
422 long id = flowManager.getNextFlowEntryId();
423 flowEntry.setFlowEntryId(new FlowEntryId(id));
424 }
425 }
426 }
427
428 /**
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800429 * Prepare my flows.
430 *
431 * @param mySwitches the collection of my switches.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800432 */
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800433 private void prepareMyFlows(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800434 // Fetch my flows from the database
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800435 ArrayList<FlowPath> myFlows = flowManager.getAllMyFlows(mySwitches);
436 for (FlowPath flowPath : myFlows) {
437 allFlowPaths.put(flowPath.flowId().value(), flowPath);
438 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800439
440 //
441 // Automatically add all Flow ID events (for the Flows this instance
442 // is responsible for) to the collection of Flows to recompute.
443 //
444 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
445 FlowId flowId = eventEntry.eventData();
446 FlowPath flowPath = allFlowPaths.get(flowId.value());
447 if (flowPath != null) {
448 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
449 flowPath);
450 }
451 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800452 }
453
454 /**
455 * Process the Flow ID events.
456 *
457 * @param mySwitches the collection of my switches.
458 * @return a collection of modified Flow Entries this instance needs
459 * to push to its own switches.
460 */
461 private Collection<FlowEntry> processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
462 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
463
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800464 //
465 // Process all Flow ID events and update the appropriate state
466 //
467 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
468 FlowId flowId = eventEntry.eventData();
469
470 log.debug("Flow ID Event: {} {}", eventEntry.eventType(), flowId);
471
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800472 //
473 // Lookup the Flow ID in the Flows that were read from the
474 // database in in a previous step. If not found, read from
475 // the database.
476 //
477 FlowPath flowPath = allFlowPaths.get(flowId.value());
478 if (flowPath == null)
479 flowPath = flowManager.getFlow(flowId);
480 if (flowPath == null) {
481 log.debug("Flow ID {} : Flow not found!", flowId);
482 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800483 }
484
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800485 // Collect only my flow entries that are not updated.
486 for (FlowEntry flowEntry : flowPath.flowEntries()) {
487 if (flowEntry.flowEntrySwitchState() !=
488 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
489 continue;
490 }
491 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
492 if (mySwitch == null)
493 continue;
494 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800495 }
496 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800497
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800498 return modifiedFlowEntries;
499 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800500
501 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800502 * Process the Flow Path events.
503 */
504 private void processFlowPathEvents() {
505 //
506 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700507 //
508 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
509 FlowPath flowPath = eventEntry.eventData();
510
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800511 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800512
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700513 switch (eventEntry.eventType()) {
514 case ENTRY_ADD: {
515 //
516 // Add a new Flow Path
517 //
518 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
519 //
520 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800521 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700522 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700523 }
524
525 switch (flowPath.flowPathType()) {
526 case FP_TYPE_SHORTEST_PATH:
527 //
528 // Reset the Data Path, in case it was set already, because
529 // we are going to recompute it anyway.
530 //
531 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800532 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
533 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700534 break;
535 case FP_TYPE_EXPLICIT_PATH:
536 //
537 // Mark all Flow Entries for installation in the switches.
538 //
539 for (FlowEntry flowEntry : flowPath.flowEntries()) {
540 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
541 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800542 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700543 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800544 case FP_TYPE_UNKNOWN:
545 log.error("FlowPath event with unknown type");
546 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700547 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800548 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700549
550 break;
551 }
552
553 case ENTRY_REMOVE: {
554 //
555 // Remove an existing Flow Path.
556 //
557 // Find the Flow Path, and mark the Flow and its Flow Entries
558 // for deletion.
559 //
560 FlowPath existingFlowPath =
561 allFlowPaths.get(flowPath.flowId().value());
562 if (existingFlowPath == null)
563 continue; // Nothing to do
564
565 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
566 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
567 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
568 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
569 }
570
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800571 // Remove the Flow Path from the internal state
572 Long key = existingFlowPath.flowId().value();
573 allFlowPaths.remove(key);
574 shouldRecomputeFlowPaths.remove(key);
575 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700576
577 break;
578 }
579 }
580 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800581 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700582
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800583 /**
584 * Process the Topology events.
585 */
586 private void processTopologyEvents() {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800587 if (enableOnrc2014MeasurementsTopology) {
588 if (topologyEvents.isEmpty())
589 return;
590 log.debug("[BEFORE] {}", topology.toString());
591 topology.readFromDatabase(dbHandler);
592 log.debug("[AFTER] {}", topology.toString());
593 shouldRecomputeFlowPaths.putAll(allFlowPaths);
594 return;
595 }
596
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700597 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800598 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700599 //
600 boolean isTopologyModified = false;
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800601 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
602 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800603
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800604 log.debug("Topology Event: {} {}", eventEntry.eventType(),
605 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800606
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800607 switch (eventEntry.eventType()) {
608 case ENTRY_ADD:
609 isTopologyModified |= topology.addTopologyElement(topologyElement);
610 break;
611 case ENTRY_REMOVE:
612 isTopologyModified |= topology.removeTopologyElement(topologyElement);
613 break;
614 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700615 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700616 if (isTopologyModified) {
617 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800618 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700619 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800620 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700621
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800622 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800623 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800624 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800625 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800626 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800627 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800628
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700629 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800630 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700631 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800632 if (! unmatchedFlowEntryAdd.isEmpty()) {
633 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
634 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800635 // log.debug("Processing Unmatched Flow Entry: {}",
636 // flowEntry.toString());
637
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800638 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800639 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800640 remainingUpdates.put(flowEntry.flowEntryId().value(),
641 flowEntry);
642 continue;
643 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800644 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
645 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800646 remainingUpdates.put(flowEntry.flowEntryId().value(),
647 flowEntry);
648 continue;
649 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800650 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
651 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
652 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700653 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800654 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700655 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800656 }
657
658 /**
659 * Process the Flow Entry events.
660 */
661 private void processFlowEntryEvents() {
662 FlowPath flowPath;
663 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700664
665 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800666 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700667 //
668 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
669 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800670
671 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800672 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800673
674 if ((! flowEntry.isValidFlowId()) ||
675 (! flowEntry.isValidFlowEntryId())) {
676 continue;
677 }
678
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700679 switch (eventEntry.eventType()) {
680 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800681 flowPath = allFlowPaths.get(flowEntry.flowId().value());
682 if (flowPath == null) {
683 // Flow Path not found: keep the entry for later matching
684 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
685 flowEntry);
686 break;
687 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800688 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
689 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800690 // Flow Entry not found: keep the entry for later matching
691 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
692 flowEntry);
693 break;
694 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800695 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
696 // Add the updated Flow Path to the list of updated paths
697 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
698 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700699 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800700
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700701 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800702 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
703 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800704 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800705 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800706
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800707 flowPath = allFlowPaths.get(flowEntry.flowId().value());
708 if (flowPath == null) {
709 // Flow Path not found: ignore the update
710 break;
711 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800712 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
713 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800714 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800715 break;
716 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800717 if (updateFlowEntryRemove(flowPath, localFlowEntry,
718 flowEntry)) {
719 // Add the updated Flow Path to the list of updated paths
720 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
721 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700722 break;
723 }
724 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700725 }
726
727 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800728 * Find a Flow Entry that should be updated because of an external
729 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700730 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800731 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800732 * @param newFlowEntry the FlowEntry with the new state.
733 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700734 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800735 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
736 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700737 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800738 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700739 //
740 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800741 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800742 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700743 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800744 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700745
746 //
747 // Local Flow Entry match found
748 //
749 if (localFlowEntry.isValidFlowEntryId()) {
750 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800751 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700752 //
753 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800754 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700755 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800756 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700757 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700758 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800759 return localFlowEntry;
760 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700761
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800762 return null; // Entry not found
763 }
764
765 /**
766 * Update a Flow Entry because of an external ENTRY_ADD event.
767 *
768 * @param flowPath the FlowPath for the Flow Entry to update.
769 * @param localFlowEntry the local Flow Entry to update.
770 * @param newFlowEntry the FlowEntry with the new state.
771 * @return true if the local Flow Entry was updated, otherwise false.
772 */
773 private boolean updateFlowEntryAdd(FlowPath flowPath,
774 FlowEntry localFlowEntry,
775 FlowEntry newFlowEntry) {
776 boolean updated = false;
777
778 if (localFlowEntry.flowEntryUserState() ==
779 FlowEntryUserState.FE_USER_DELETE) {
780 // Don't add-back a Flow Entry that is already deleted
781 return false;
782 }
783
784 if (! localFlowEntry.isValidFlowEntryId()) {
785 // Update the Flow Entry ID
786 FlowEntryId flowEntryId =
787 new FlowEntryId(newFlowEntry.flowEntryId().value());
788 localFlowEntry.setFlowEntryId(flowEntryId);
789 updated = true;
790 }
791
792 //
793 // Update the local Flow Entry, and keep state to check
794 // if the Flow Path has been installed.
795 //
796 if (localFlowEntry.flowEntryUserState() !=
797 newFlowEntry.flowEntryUserState()) {
798 localFlowEntry.setFlowEntryUserState(
799 newFlowEntry.flowEntryUserState());
800 updated = true;
801 }
802 if (localFlowEntry.flowEntrySwitchState() !=
803 newFlowEntry.flowEntrySwitchState()) {
804 localFlowEntry.setFlowEntrySwitchState(
805 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800806 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800807 updated = true;
808 }
809
810 return updated;
811 }
812
813 /**
814 * Find a Flow Entry that should be updated because of an external
815 * ENTRY_REMOVE event.
816 *
817 * @param flowPath the FlowPath for the Flow Entry to update.
818 * @param newFlowEntry the FlowEntry with the new state.
819 * @return the Flow Entry that should be updated if found, otherwise null.
820 */
821 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
822 FlowEntry newFlowEntry) {
823 //
824 // Iterate over all Flow Entries and find a match based on
825 // the Flow Entry ID.
826 //
827 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
828 if (! localFlowEntry.isValidFlowEntryId())
829 continue;
830 if (localFlowEntry.flowEntryId().value() !=
831 newFlowEntry.flowEntryId().value()) {
832 continue;
833 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800834 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700835 }
836
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800837 return null; // Entry not found
838 }
839
840 /**
841 * Update a Flow Entry because of an external ENTRY_REMOVE event.
842 *
843 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800844 * @param localFlowEntry the local Flow Entry to update.
845 * @param newFlowEntry the FlowEntry with the new state.
846 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800847 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800848 private boolean updateFlowEntryRemove(FlowPath flowPath,
849 FlowEntry localFlowEntry,
850 FlowEntry newFlowEntry) {
851 boolean updated = false;
852
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800853 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800854 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800855 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800856 if (localFlowEntry.flowEntryUserState() !=
857 newFlowEntry.flowEntryUserState()) {
858 localFlowEntry.setFlowEntryUserState(
859 newFlowEntry.flowEntryUserState());
860 updated = true;
861 }
862 if (localFlowEntry.flowEntrySwitchState() !=
863 newFlowEntry.flowEntrySwitchState()) {
864 localFlowEntry.setFlowEntrySwitchState(
865 newFlowEntry.flowEntrySwitchState());
866 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800867 }
868
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800869 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700870 }
871
872 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700873 * Recompute a Flow Path.
874 *
875 * @param flowPath the Flow Path to recompute.
876 * @return true if the recomputed Flow Path has changed, otherwise false.
877 */
878 private boolean recomputeFlowPath(FlowPath flowPath) {
879 boolean hasChanged = false;
880
881 //
882 // Test whether the Flow Path needs to be recomputed
883 //
884 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700885 case FP_TYPE_UNKNOWN:
886 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700887 case FP_TYPE_SHORTEST_PATH:
888 break;
889 case FP_TYPE_EXPLICIT_PATH:
890 return false; // An explicit path never changes
891 }
892
893 DataPath oldDataPath = flowPath.dataPath();
894
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700895 // Compute the new path
896 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
897 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700898 if (newDataPath == null) {
899 // We need the DataPath to compare the paths
900 newDataPath = new DataPath();
901 }
902 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
903
904 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700905 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700906 //
907 if (oldDataPath.flowEntries().size() !=
908 newDataPath.flowEntries().size()) {
909 hasChanged = true;
910 } else {
911 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
912 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
913 while (oldIter.hasNext() && newIter.hasNext()) {
914 FlowEntry oldFlowEntry = oldIter.next();
915 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700916 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
917 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700918 hasChanged = true;
919 break;
920 }
921 }
922 }
923 if (! hasChanged)
924 return hasChanged;
925
926 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700927 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700928 // - If a Flow Entry for a switch is in the old data path, but not
929 // in the new data path, then mark it for deletion.
930 // - If a Flow Entry for a switch is in the new data path, but not
931 // in the old data path, then mark it for addition.
932 // - If a Flow Entry for a switch is in both the old and the new
933 // data path, but it has changed, e.g., the incoming and/or outgoing
934 // port(s), then mark the old Flow Entry for deletion, and mark
935 // the new Flow Entry for addition.
936 // - If a Flow Entry for a switch is in both the old and the new
937 // data path, and it hasn't changed, then just keep it.
938 //
939 // NOTE: We use the Switch DPID of each entry to match the entries
940 //
941 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
942 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
943 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
944 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
945
946 // Prepare maps with the Flow Entries, so they are fast to lookup
947 for (FlowEntry flowEntry : oldDataPath.flowEntries())
948 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
949 for (FlowEntry flowEntry : newDataPath.flowEntries())
950 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
951
952 //
953 // Find the old Flow Entries that should be deleted
954 //
955 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
956 FlowEntry newFlowEntry =
957 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
958 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800959 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700960 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
961 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
962 deletedFlowEntries.add(oldFlowEntry);
963 }
964 }
965
966 //
967 // Find the new Flow Entries that should be added or updated
968 //
969 int idx = 0;
970 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
971 FlowEntry oldFlowEntry =
972 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
973
974 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700975 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
976 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700977 //
978 // Both Flow Entries are same
979 //
980 finalFlowEntries.add(oldFlowEntry);
981 idx++;
982 continue;
983 }
984
985 if (oldFlowEntry != null) {
986 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800987 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700988 //
989 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
990 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
991 deletedFlowEntries.add(oldFlowEntry);
992 }
993
994 //
995 // Add the new Flow Entry
996 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700997 //
998 // NOTE: Assign only the Flow ID.
999 // The Flow Entry ID is assigned later only for the Flow Entries
1000 // this instance is responsible for.
1001 //
1002 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001003
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001004 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001005 // Copy the Flow timeouts
1006 //
1007 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1008 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1009
1010 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001011 // Allocate the FlowEntryMatch by copying the default one
1012 // from the FlowPath (if set).
1013 //
1014 FlowEntryMatch flowEntryMatch = null;
1015 if (flowPath.flowEntryMatch() != null)
1016 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1017 else
1018 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001019 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001020
1021 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001022 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1023
1024 //
1025 // Set the actions:
1026 // If the first Flow Entry, copy the Flow Path actions to it.
1027 //
1028 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1029 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1030 FlowEntryActions flowActions =
1031 new FlowEntryActions(flowPath.flowEntryActions());
1032 for (FlowEntryAction action : flowActions.actions())
1033 flowEntryActions.addAction(action);
1034 }
1035 idx++;
1036
1037 //
1038 // Add the outgoing port output action
1039 //
1040 FlowEntryAction flowEntryAction = new FlowEntryAction();
1041 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1042 flowEntryActions.addAction(flowEntryAction);
1043
1044 //
1045 // Set the state of the new Flow Entry
1046 //
1047 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1048 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1049 finalFlowEntries.add(newFlowEntry);
1050 }
1051
1052 //
1053 // Replace the old Flow Entries with the new Flow Entries.
1054 // Note that the Flow Entries that will be deleted are added at
1055 // the end.
1056 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001057 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001058 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1059
1060 return hasChanged;
1061 }
1062
1063 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001064 * Receive a notification that a Flow is added.
1065 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001066 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001067 */
1068 @Override
1069 public void notificationRecvFlowAdded(FlowPath flowPath) {
1070 EventEntry<FlowPath> eventEntry =
1071 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1072 networkEvents.add(eventEntry);
1073 }
1074
1075 /**
1076 * Receive a notification that a Flow is removed.
1077 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001078 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001079 */
1080 @Override
1081 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1082 EventEntry<FlowPath> eventEntry =
1083 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1084 networkEvents.add(eventEntry);
1085 }
1086
1087 /**
1088 * Receive a notification that a Flow is updated.
1089 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001090 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001091 */
1092 @Override
1093 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1094 // NOTE: The ADD and UPDATE events are processed in same way
1095 EventEntry<FlowPath> eventEntry =
1096 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1097 networkEvents.add(eventEntry);
1098 }
1099
1100 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001101 * Receive a notification that a FlowEntry is added.
1102 *
1103 * @param flowEntry the FlowEntry that is added.
1104 */
1105 @Override
1106 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
1107 EventEntry<FlowEntry> eventEntry =
1108 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1109 networkEvents.add(eventEntry);
1110 }
1111
1112 /**
1113 * Receive a notification that a FlowEntry is removed.
1114 *
1115 * @param flowEntry the FlowEntry that is removed.
1116 */
1117 @Override
1118 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
1119 EventEntry<FlowEntry> eventEntry =
1120 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1121 networkEvents.add(eventEntry);
1122 }
1123
1124 /**
1125 * Receive a notification that a FlowEntry is updated.
1126 *
1127 * @param flowEntry the FlowEntry that is updated.
1128 */
1129 @Override
1130 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1131 // NOTE: The ADD and UPDATE events are processed in same way
1132 EventEntry<FlowEntry> eventEntry =
1133 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1134 networkEvents.add(eventEntry);
1135 }
1136
1137 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001138 * Receive a notification that a FlowId is added.
1139 *
1140 * @param flowId the FlowId that is added.
1141 */
1142 @Override
1143 public void notificationRecvFlowIdAdded(FlowId flowId) {
1144 EventEntry<FlowId> eventEntry =
1145 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1146 networkEvents.add(eventEntry);
1147 }
1148
1149 /**
1150 * Receive a notification that a FlowId is removed.
1151 *
1152 * @param flowId the FlowId that is removed.
1153 */
1154 @Override
1155 public void notificationRecvFlowIdRemoved(FlowId flowId) {
1156 EventEntry<FlowId> eventEntry =
1157 new EventEntry<FlowId>(EventEntry.Type.ENTRY_REMOVE, flowId);
1158 networkEvents.add(eventEntry);
1159 }
1160
1161 /**
1162 * Receive a notification that a FlowId is updated.
1163 *
1164 * @param flowId the FlowId that is updated.
1165 */
1166 @Override
1167 public void notificationRecvFlowIdUpdated(FlowId flowId) {
1168 // NOTE: The ADD and UPDATE events are processed in same way
1169 EventEntry<FlowId> eventEntry =
1170 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1171 networkEvents.add(eventEntry);
1172 }
1173
1174 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001175 * Receive a notification that a Topology Element is added.
1176 *
1177 * @param topologyElement the Topology Element that is added.
1178 */
1179 @Override
1180 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1181 EventEntry<TopologyElement> eventEntry =
1182 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1183 networkEvents.add(eventEntry);
1184 }
1185
1186 /**
1187 * Receive a notification that a Topology Element is removed.
1188 *
1189 * @param topologyElement the Topology Element that is removed.
1190 */
1191 @Override
1192 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1193 EventEntry<TopologyElement> eventEntry =
1194 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1195 networkEvents.add(eventEntry);
1196 }
1197
1198 /**
1199 * Receive a notification that a Topology Element is updated.
1200 *
1201 * @param topologyElement the Topology Element that is updated.
1202 */
1203 @Override
1204 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1205 // NOTE: The ADD and UPDATE events are processed in same way
1206 EventEntry<TopologyElement> eventEntry =
1207 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1208 networkEvents.add(eventEntry);
1209 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001210
1211 /**
1212 * Get a sorted copy of all Flow Paths.
1213 *
1214 * @return a sorted copy of all Flow Paths.
1215 */
1216 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1217 SortedMap<Long, FlowPath> sortedFlowPaths =
1218 new TreeMap<Long, FlowPath>();
1219
1220 //
1221 // TODO: For now we use serialization/deserialization to create
1222 // a copy of each Flow Path. In the future, we should use proper
1223 // copy constructors.
1224 //
1225 Kryo kryo = kryoFactory.newKryo();
1226 synchronized (allFlowPaths) {
1227 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1228 FlowPath origFlowPath = entry.getValue();
1229 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1230 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1231 }
1232 }
1233 kryoFactory.deleteKryo(kryo);
1234
1235 return sortedFlowPaths;
1236 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001237}