blob: 997966455565f5519e4949d1894dcd61378d9576 [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
49 private boolean enableOnrc2014MeasurementsFlows = false;
50 private boolean enableOnrc2014MeasurementsTopology = false;
51
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 Radoslavovb7506842013-10-29 17:46:54 -0700243 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800244 flowEntryEvents.isEmpty() && flowIdEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700245 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700246 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700247
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800248 processFlowIdEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800249 processFlowPathEvents();
250 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800251 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800252 processFlowEntryEvents();
253
254 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800255 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800256 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800257 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800258 }
259
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800260 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800261 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800262
263 // Assign missing Flow Entry IDs
264 assignFlowEntryId(modifiedFlowEntries);
265
266 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800267 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800268 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800269 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
270 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800271
272 //
273 // Remove Flow Entries that were deleted
274 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800275 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800276 flowPath.dataPath().removeDeletedFlowEntries();
277
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800278 //
279 // Check if Flow Paths have been installed into all switches,
280 // and generate the appropriate events.
281 //
282 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
283
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800284 // Cleanup
285 topologyEvents.clear();
286 flowPathEvents.clear();
287 flowEntryEvents.clear();
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800288 flowIdEvents.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800289 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800290 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800291 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800292 checkIfInstalledFlowPaths.clear();
293 }
294
295 /**
296 * Check if Flow Paths have been installed into all switches,
297 * and generate the appropriate events.
298 *
299 * @param flowPaths the flowPaths to process.
300 */
301 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
302 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
303
304 Kryo kryo = kryoFactory.newKryo();
305
306 for (FlowPath flowPath : flowPaths) {
307 boolean isInstalled = true;
308
309 //
310 // Check whether all Flow Entries have been installed
311 //
312 for (FlowEntry flowEntry : flowPath.flowEntries()) {
313 if (flowEntry.flowEntrySwitchState() !=
314 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
315 isInstalled = false;
316 break;
317 }
318 }
319
320 if (isInstalled) {
321 // Create a copy and add it to the list
322 FlowPath copyFlowPath = kryo.copy(flowPath);
323 installedFlowPaths.add(copyFlowPath);
324 }
325 }
326 kryoFactory.deleteKryo(kryo);
327
328 // Generate an event for the installed Flow Path.
329 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800330 }
331
332 /**
333 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800334 *
335 * @param modifiedFlowPaths the Flow Paths to process.
336 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800337 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800338 private Collection<FlowEntry> extractModifiedFlowEntries(
339 Collection<FlowPath> modifiedFlowPaths) {
340 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800341
342 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800343 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800344 for (FlowEntry flowEntry : flowPath.flowEntries()) {
345 if (flowEntry.flowEntrySwitchState() ==
346 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800347 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800348 }
349 }
350 }
351 return modifiedFlowEntries;
352 }
353
354 /**
355 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800356 *
357 * @param modifiedFlowEnries the collection of Flow Entries that need
358 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800359 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800360 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800361 if (modifiedFlowEntries.isEmpty())
362 return;
363
364 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
365
366 //
367 // Assign the Flow Entry ID only for Flow Entries for my switches
368 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800369 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800370 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
371 if (mySwitch == null)
372 continue;
373 if (! flowEntry.isValidFlowEntryId()) {
374 long id = flowManager.getNextFlowEntryId();
375 flowEntry.setFlowEntryId(new FlowEntryId(id));
376 }
377 }
378 }
379
380 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800381 * Process the Flow ID events.
382 */
383 private void processFlowIdEvents() {
384 //
385 // Process all Flow ID events and update the appropriate state
386 //
387 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
388 FlowId flowId = eventEntry.eventData();
389
390 log.debug("Flow ID Event: {} {}", eventEntry.eventType(), flowId);
391
392 switch (eventEntry.eventType()) {
393 case ENTRY_ADD: {
394 //
395 // Add a new Flow ID
396 //
397 // TODO: Implement it!
398
399 break;
400 }
401
402 case ENTRY_REMOVE: {
403 //
404 // Remove an existing Flow ID.
405 //
406 // TODO: Implement it!
407
408 break;
409 }
410 }
411 }
412 }
413
414
415 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800416 * Process the Flow Path events.
417 */
418 private void processFlowPathEvents() {
419 //
420 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700421 //
422 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
423 FlowPath flowPath = eventEntry.eventData();
424
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800425 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800426
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700427 switch (eventEntry.eventType()) {
428 case ENTRY_ADD: {
429 //
430 // Add a new Flow Path
431 //
432 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
433 //
434 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800435 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700436 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700437 }
438
439 switch (flowPath.flowPathType()) {
440 case FP_TYPE_SHORTEST_PATH:
441 //
442 // Reset the Data Path, in case it was set already, because
443 // we are going to recompute it anyway.
444 //
445 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800446 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
447 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700448 break;
449 case FP_TYPE_EXPLICIT_PATH:
450 //
451 // Mark all Flow Entries for installation in the switches.
452 //
453 for (FlowEntry flowEntry : flowPath.flowEntries()) {
454 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
455 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800456 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700457 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800458 case FP_TYPE_UNKNOWN:
459 log.error("FlowPath event with unknown type");
460 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700461 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800462 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700463
464 break;
465 }
466
467 case ENTRY_REMOVE: {
468 //
469 // Remove an existing Flow Path.
470 //
471 // Find the Flow Path, and mark the Flow and its Flow Entries
472 // for deletion.
473 //
474 FlowPath existingFlowPath =
475 allFlowPaths.get(flowPath.flowId().value());
476 if (existingFlowPath == null)
477 continue; // Nothing to do
478
479 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
480 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
481 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
482 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
483 }
484
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800485 // Remove the Flow Path from the internal state
486 Long key = existingFlowPath.flowId().value();
487 allFlowPaths.remove(key);
488 shouldRecomputeFlowPaths.remove(key);
489 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700490
491 break;
492 }
493 }
494 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800495 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700496
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800497 /**
498 * Process the Topology events.
499 */
500 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700501 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800502 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700503 //
504 boolean isTopologyModified = false;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800505 if (enableOnrc2014MeasurementsTopology) {
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800506 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800507 topology.readFromDatabase(dbHandler);
508 isTopologyModified = true;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800509 log.debug("[AFTER] {}", topology.toString());
510 } else {
511 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
512 TopologyElement topologyElement = eventEntry.eventData();
513
514 log.debug("Topology Event: {} {}", eventEntry.eventType(),
515 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800516
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800517 switch (eventEntry.eventType()) {
518 case ENTRY_ADD:
519 isTopologyModified |= topology.addTopologyElement(topologyElement);
520 break;
521 case ENTRY_REMOVE:
522 isTopologyModified |= topology.removeTopologyElement(topologyElement);
523 break;
524 }
525 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700526 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700527 if (isTopologyModified) {
528 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800529 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700530 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800531 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700532
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800533 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800534 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800535 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800536 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800537 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800538 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800539
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700540 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800541 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700542 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800543 if (! unmatchedFlowEntryAdd.isEmpty()) {
544 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
545 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800546 // log.debug("Processing Unmatched Flow Entry: {}",
547 // flowEntry.toString());
548
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800549 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800550 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800551 remainingUpdates.put(flowEntry.flowEntryId().value(),
552 flowEntry);
553 continue;
554 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800555 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
556 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800557 remainingUpdates.put(flowEntry.flowEntryId().value(),
558 flowEntry);
559 continue;
560 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800561 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
562 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
563 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700564 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800565 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700566 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800567 }
568
569 /**
570 * Process the Flow Entry events.
571 */
572 private void processFlowEntryEvents() {
573 FlowPath flowPath;
574 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700575
576 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800577 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700578 //
579 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
580 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800581
582 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800583 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800584
585 if ((! flowEntry.isValidFlowId()) ||
586 (! flowEntry.isValidFlowEntryId())) {
587 continue;
588 }
589
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700590 switch (eventEntry.eventType()) {
591 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800592 flowPath = allFlowPaths.get(flowEntry.flowId().value());
593 if (flowPath == null) {
594 // Flow Path not found: keep the entry for later matching
595 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
596 flowEntry);
597 break;
598 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800599 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
600 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800601 // Flow Entry not found: keep the entry for later matching
602 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
603 flowEntry);
604 break;
605 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800606 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
607 // Add the updated Flow Path to the list of updated paths
608 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
609 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700610 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800611
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700612 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800613 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
614 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800615 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800616 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800617
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800618 flowPath = allFlowPaths.get(flowEntry.flowId().value());
619 if (flowPath == null) {
620 // Flow Path not found: ignore the update
621 break;
622 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800623 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
624 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800625 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800626 break;
627 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800628 if (updateFlowEntryRemove(flowPath, localFlowEntry,
629 flowEntry)) {
630 // Add the updated Flow Path to the list of updated paths
631 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
632 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700633 break;
634 }
635 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700636 }
637
638 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800639 * Find a Flow Entry that should be updated because of an external
640 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700641 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800642 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800643 * @param newFlowEntry the FlowEntry with the new state.
644 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700645 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800646 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
647 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700648 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800649 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700650 //
651 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800652 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800653 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700654 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800655 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700656
657 //
658 // Local Flow Entry match found
659 //
660 if (localFlowEntry.isValidFlowEntryId()) {
661 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800662 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700663 //
664 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800665 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700666 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800667 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700668 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700669 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800670 return localFlowEntry;
671 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700672
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800673 return null; // Entry not found
674 }
675
676 /**
677 * Update a Flow Entry because of an external ENTRY_ADD event.
678 *
679 * @param flowPath the FlowPath for the Flow Entry to update.
680 * @param localFlowEntry the local Flow Entry to update.
681 * @param newFlowEntry the FlowEntry with the new state.
682 * @return true if the local Flow Entry was updated, otherwise false.
683 */
684 private boolean updateFlowEntryAdd(FlowPath flowPath,
685 FlowEntry localFlowEntry,
686 FlowEntry newFlowEntry) {
687 boolean updated = false;
688
689 if (localFlowEntry.flowEntryUserState() ==
690 FlowEntryUserState.FE_USER_DELETE) {
691 // Don't add-back a Flow Entry that is already deleted
692 return false;
693 }
694
695 if (! localFlowEntry.isValidFlowEntryId()) {
696 // Update the Flow Entry ID
697 FlowEntryId flowEntryId =
698 new FlowEntryId(newFlowEntry.flowEntryId().value());
699 localFlowEntry.setFlowEntryId(flowEntryId);
700 updated = true;
701 }
702
703 //
704 // Update the local Flow Entry, and keep state to check
705 // if the Flow Path has been installed.
706 //
707 if (localFlowEntry.flowEntryUserState() !=
708 newFlowEntry.flowEntryUserState()) {
709 localFlowEntry.setFlowEntryUserState(
710 newFlowEntry.flowEntryUserState());
711 updated = true;
712 }
713 if (localFlowEntry.flowEntrySwitchState() !=
714 newFlowEntry.flowEntrySwitchState()) {
715 localFlowEntry.setFlowEntrySwitchState(
716 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800717 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800718 updated = true;
719 }
720
721 return updated;
722 }
723
724 /**
725 * Find a Flow Entry that should be updated because of an external
726 * ENTRY_REMOVE event.
727 *
728 * @param flowPath the FlowPath for the Flow Entry to update.
729 * @param newFlowEntry the FlowEntry with the new state.
730 * @return the Flow Entry that should be updated if found, otherwise null.
731 */
732 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
733 FlowEntry newFlowEntry) {
734 //
735 // Iterate over all Flow Entries and find a match based on
736 // the Flow Entry ID.
737 //
738 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
739 if (! localFlowEntry.isValidFlowEntryId())
740 continue;
741 if (localFlowEntry.flowEntryId().value() !=
742 newFlowEntry.flowEntryId().value()) {
743 continue;
744 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800745 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700746 }
747
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800748 return null; // Entry not found
749 }
750
751 /**
752 * Update a Flow Entry because of an external ENTRY_REMOVE event.
753 *
754 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800755 * @param localFlowEntry the local Flow Entry to update.
756 * @param newFlowEntry the FlowEntry with the new state.
757 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800758 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800759 private boolean updateFlowEntryRemove(FlowPath flowPath,
760 FlowEntry localFlowEntry,
761 FlowEntry newFlowEntry) {
762 boolean updated = false;
763
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800764 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800765 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800766 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800767 if (localFlowEntry.flowEntryUserState() !=
768 newFlowEntry.flowEntryUserState()) {
769 localFlowEntry.setFlowEntryUserState(
770 newFlowEntry.flowEntryUserState());
771 updated = true;
772 }
773 if (localFlowEntry.flowEntrySwitchState() !=
774 newFlowEntry.flowEntrySwitchState()) {
775 localFlowEntry.setFlowEntrySwitchState(
776 newFlowEntry.flowEntrySwitchState());
777 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800778 }
779
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800780 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700781 }
782
783 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700784 * Recompute a Flow Path.
785 *
786 * @param flowPath the Flow Path to recompute.
787 * @return true if the recomputed Flow Path has changed, otherwise false.
788 */
789 private boolean recomputeFlowPath(FlowPath flowPath) {
790 boolean hasChanged = false;
791
792 //
793 // Test whether the Flow Path needs to be recomputed
794 //
795 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700796 case FP_TYPE_UNKNOWN:
797 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700798 case FP_TYPE_SHORTEST_PATH:
799 break;
800 case FP_TYPE_EXPLICIT_PATH:
801 return false; // An explicit path never changes
802 }
803
804 DataPath oldDataPath = flowPath.dataPath();
805
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700806 // Compute the new path
807 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
808 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700809 if (newDataPath == null) {
810 // We need the DataPath to compare the paths
811 newDataPath = new DataPath();
812 }
813 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
814
815 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700816 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700817 //
818 if (oldDataPath.flowEntries().size() !=
819 newDataPath.flowEntries().size()) {
820 hasChanged = true;
821 } else {
822 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
823 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
824 while (oldIter.hasNext() && newIter.hasNext()) {
825 FlowEntry oldFlowEntry = oldIter.next();
826 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700827 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
828 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700829 hasChanged = true;
830 break;
831 }
832 }
833 }
834 if (! hasChanged)
835 return hasChanged;
836
837 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700838 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700839 // - If a Flow Entry for a switch is in the old data path, but not
840 // in the new data path, then mark it for deletion.
841 // - If a Flow Entry for a switch is in the new data path, but not
842 // in the old data path, then mark it for addition.
843 // - If a Flow Entry for a switch is in both the old and the new
844 // data path, but it has changed, e.g., the incoming and/or outgoing
845 // port(s), then mark the old Flow Entry for deletion, and mark
846 // the new Flow Entry for addition.
847 // - If a Flow Entry for a switch is in both the old and the new
848 // data path, and it hasn't changed, then just keep it.
849 //
850 // NOTE: We use the Switch DPID of each entry to match the entries
851 //
852 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
853 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
854 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
855 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
856
857 // Prepare maps with the Flow Entries, so they are fast to lookup
858 for (FlowEntry flowEntry : oldDataPath.flowEntries())
859 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
860 for (FlowEntry flowEntry : newDataPath.flowEntries())
861 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
862
863 //
864 // Find the old Flow Entries that should be deleted
865 //
866 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
867 FlowEntry newFlowEntry =
868 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
869 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800870 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700871 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
872 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
873 deletedFlowEntries.add(oldFlowEntry);
874 }
875 }
876
877 //
878 // Find the new Flow Entries that should be added or updated
879 //
880 int idx = 0;
881 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
882 FlowEntry oldFlowEntry =
883 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
884
885 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700886 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
887 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700888 //
889 // Both Flow Entries are same
890 //
891 finalFlowEntries.add(oldFlowEntry);
892 idx++;
893 continue;
894 }
895
896 if (oldFlowEntry != null) {
897 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800898 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700899 //
900 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
901 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
902 deletedFlowEntries.add(oldFlowEntry);
903 }
904
905 //
906 // Add the new Flow Entry
907 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700908 //
909 // NOTE: Assign only the Flow ID.
910 // The Flow Entry ID is assigned later only for the Flow Entries
911 // this instance is responsible for.
912 //
913 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700914
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800915 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800916 // Copy the Flow timeouts
917 //
918 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
919 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
920
921 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800922 // Allocate the FlowEntryMatch by copying the default one
923 // from the FlowPath (if set).
924 //
925 FlowEntryMatch flowEntryMatch = null;
926 if (flowPath.flowEntryMatch() != null)
927 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
928 else
929 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700930 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800931
932 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700933 flowEntryMatch.enableInPort(newFlowEntry.inPort());
934
935 //
936 // Set the actions:
937 // If the first Flow Entry, copy the Flow Path actions to it.
938 //
939 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
940 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
941 FlowEntryActions flowActions =
942 new FlowEntryActions(flowPath.flowEntryActions());
943 for (FlowEntryAction action : flowActions.actions())
944 flowEntryActions.addAction(action);
945 }
946 idx++;
947
948 //
949 // Add the outgoing port output action
950 //
951 FlowEntryAction flowEntryAction = new FlowEntryAction();
952 flowEntryAction.setActionOutput(newFlowEntry.outPort());
953 flowEntryActions.addAction(flowEntryAction);
954
955 //
956 // Set the state of the new Flow Entry
957 //
958 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
959 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
960 finalFlowEntries.add(newFlowEntry);
961 }
962
963 //
964 // Replace the old Flow Entries with the new Flow Entries.
965 // Note that the Flow Entries that will be deleted are added at
966 // the end.
967 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800968 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700969 flowPath.dataPath().setFlowEntries(finalFlowEntries);
970
971 return hasChanged;
972 }
973
974 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700975 * Receive a notification that a Flow is added.
976 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700977 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700978 */
979 @Override
980 public void notificationRecvFlowAdded(FlowPath flowPath) {
981 EventEntry<FlowPath> eventEntry =
982 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
983 networkEvents.add(eventEntry);
984 }
985
986 /**
987 * Receive a notification that a Flow is removed.
988 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700989 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700990 */
991 @Override
992 public void notificationRecvFlowRemoved(FlowPath flowPath) {
993 EventEntry<FlowPath> eventEntry =
994 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
995 networkEvents.add(eventEntry);
996 }
997
998 /**
999 * Receive a notification that a Flow is updated.
1000 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001001 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001002 */
1003 @Override
1004 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1005 // NOTE: The ADD and UPDATE events are processed in same way
1006 EventEntry<FlowPath> eventEntry =
1007 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1008 networkEvents.add(eventEntry);
1009 }
1010
1011 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001012 * Receive a notification that a FlowEntry is added.
1013 *
1014 * @param flowEntry the FlowEntry that is added.
1015 */
1016 @Override
1017 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
1018 EventEntry<FlowEntry> eventEntry =
1019 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1020 networkEvents.add(eventEntry);
1021 }
1022
1023 /**
1024 * Receive a notification that a FlowEntry is removed.
1025 *
1026 * @param flowEntry the FlowEntry that is removed.
1027 */
1028 @Override
1029 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
1030 EventEntry<FlowEntry> eventEntry =
1031 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1032 networkEvents.add(eventEntry);
1033 }
1034
1035 /**
1036 * Receive a notification that a FlowEntry is updated.
1037 *
1038 * @param flowEntry the FlowEntry that is updated.
1039 */
1040 @Override
1041 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1042 // NOTE: The ADD and UPDATE events are processed in same way
1043 EventEntry<FlowEntry> eventEntry =
1044 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1045 networkEvents.add(eventEntry);
1046 }
1047
1048 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001049 * Receive a notification that a FlowId is added.
1050 *
1051 * @param flowId the FlowId that is added.
1052 */
1053 @Override
1054 public void notificationRecvFlowIdAdded(FlowId flowId) {
1055 EventEntry<FlowId> eventEntry =
1056 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1057 networkEvents.add(eventEntry);
1058 }
1059
1060 /**
1061 * Receive a notification that a FlowId is removed.
1062 *
1063 * @param flowId the FlowId that is removed.
1064 */
1065 @Override
1066 public void notificationRecvFlowIdRemoved(FlowId flowId) {
1067 EventEntry<FlowId> eventEntry =
1068 new EventEntry<FlowId>(EventEntry.Type.ENTRY_REMOVE, flowId);
1069 networkEvents.add(eventEntry);
1070 }
1071
1072 /**
1073 * Receive a notification that a FlowId is updated.
1074 *
1075 * @param flowId the FlowId that is updated.
1076 */
1077 @Override
1078 public void notificationRecvFlowIdUpdated(FlowId flowId) {
1079 // NOTE: The ADD and UPDATE events are processed in same way
1080 EventEntry<FlowId> eventEntry =
1081 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1082 networkEvents.add(eventEntry);
1083 }
1084
1085 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001086 * Receive a notification that a Topology Element is added.
1087 *
1088 * @param topologyElement the Topology Element that is added.
1089 */
1090 @Override
1091 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1092 EventEntry<TopologyElement> eventEntry =
1093 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1094 networkEvents.add(eventEntry);
1095 }
1096
1097 /**
1098 * Receive a notification that a Topology Element is removed.
1099 *
1100 * @param topologyElement the Topology Element that is removed.
1101 */
1102 @Override
1103 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1104 EventEntry<TopologyElement> eventEntry =
1105 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1106 networkEvents.add(eventEntry);
1107 }
1108
1109 /**
1110 * Receive a notification that a Topology Element is updated.
1111 *
1112 * @param topologyElement the Topology Element that is updated.
1113 */
1114 @Override
1115 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1116 // NOTE: The ADD and UPDATE events are processed in same way
1117 EventEntry<TopologyElement> eventEntry =
1118 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1119 networkEvents.add(eventEntry);
1120 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001121
1122 /**
1123 * Get a sorted copy of all Flow Paths.
1124 *
1125 * @return a sorted copy of all Flow Paths.
1126 */
1127 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1128 SortedMap<Long, FlowPath> sortedFlowPaths =
1129 new TreeMap<Long, FlowPath>();
1130
1131 //
1132 // TODO: For now we use serialization/deserialization to create
1133 // a copy of each Flow Path. In the future, we should use proper
1134 // copy constructors.
1135 //
1136 Kryo kryo = kryoFactory.newKryo();
1137 synchronized (allFlowPaths) {
1138 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1139 FlowPath origFlowPath = entry.getValue();
1140 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1141 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1142 }
1143 }
1144 kryoFactory.deleteKryo(kryo);
1145
1146 return sortedFlowPaths;
1147 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001148}