blob: 67a2ad114ca95bfb2e0f9e515967952a4c6759ac [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;
Yuta HIGUCHId8c37242014-01-07 11:51:29 -080011import java.util.Timer;
12import java.util.TimerTask;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080013import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070014import java.util.concurrent.BlockingQueue;
15import java.util.concurrent.LinkedBlockingQueue;
16
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080017import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070019import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070020import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070021import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070022import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070023import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070024import net.onrc.onos.ofcontroller.util.FlowEntry;
25import net.onrc.onos.ofcontroller.util.FlowEntryAction;
26import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070027import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070028import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
29import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
30import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070031import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070032import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070033import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080034import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
35
Yuta HIGUCHI2d5ac522014-01-22 10:21:41 -080036import com.esotericsoftware.kryo.Kryo;
Yuta HIGUCHIe5ef3872014-01-07 12:35:59 -080037import com.tinkerpop.blueprints.impls.ramcloud.PerfMon;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070038
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070043 * Class for FlowPath Maintenance.
44 * This class listens for FlowEvents to:
45 * - Maintain a local cache of the Network Topology.
46 * - Detect FlowPaths impacted by Topology change.
47 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070048 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070049class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070050 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070051 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070052
Yuta HIGUCHId8c37242014-01-07 11:51:29 -080053 // Flag to refresh Topology object periodically
Yuta HIGUCHIc3693022014-01-09 22:58:36 -080054 private final static boolean refreshTopology = false;
Yuta HIGUCHId8c37242014-01-07 11:51:29 -080055 // Refresh delay(ms)
56 private final static long refreshTopologyDelay = 5000;
57 // Refresh interval(ms)
Yuta HIGUCHIc3693022014-01-09 22:58:36 -080058 private final static long refreshTopologyInterval = 2000;
Yuta HIGUCHId8c37242014-01-07 11:51:29 -080059 private Timer refreshTopologyTimer;
60
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070061 private FlowManager flowManager; // The Flow Manager to use
62 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070063 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080064 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070065
66 // The queue with Flow Path and Topology Element updates
67 private BlockingQueue<EventEntry<?>> networkEvents =
68 new LinkedBlockingQueue<EventEntry<?>>();
69
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070070 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070071 private List<EventEntry<TopologyElement>> topologyEvents =
72 new LinkedList<EventEntry<TopologyElement>>();
73 private List<EventEntry<FlowPath>> flowPathEvents =
74 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070075 private List<EventEntry<FlowEntry>> flowEntryEvents =
76 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070077
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080078 // All internally computed Flow Paths
79 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
80
81 // The Flow Entries received as notifications with unmatched Flow Paths
82 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
83 new HashMap<Long, FlowEntry>();
84
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080085 //
86 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080087 // - The Flow Paths that should be recomputed
88 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080089 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080090 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080091 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
92 new HashMap<Long, FlowPath>();
93 private Map<Long, FlowPath> modifiedFlowPaths =
94 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080095 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
96 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080097
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070098 /**
99 * Constructor for a given Flow Manager and Datagrid Service.
100 *
101 * @param flowManager the Flow Manager to use.
102 * @param datagridService the Datagrid Service to use.
103 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700104 FlowEventHandler(FlowManager flowManager,
105 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700106 this.flowManager = flowManager;
107 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700108 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700109 }
110
111 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800112 * Get the network topology.
113 *
114 * @return the network topology.
115 */
116 protected Topology getTopology() { return this.topology; }
117
118 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800119 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700120 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800121 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700122 //
123 // Obtain the initial Topology state
124 //
125 Collection<TopologyElement> topologyElements =
126 datagridService.getAllTopologyElements();
127 for (TopologyElement topologyElement : topologyElements) {
128 EventEntry<TopologyElement> eventEntry =
129 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
130 topologyEvents.add(eventEntry);
131 }
132 //
133 // Obtain the initial Flow Path state
134 //
135 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
136 for (FlowPath flowPath : flowPaths) {
137 EventEntry<FlowPath> eventEntry =
138 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
139 flowPathEvents.add(eventEntry);
140 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700141 //
142 // Obtain the initial FlowEntry state
143 //
144 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
145 for (FlowEntry flowEntry : flowEntries) {
146 EventEntry<FlowEntry> eventEntry =
147 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
148 flowEntryEvents.add(eventEntry);
149 }
150
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800151 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800152 synchronized (allFlowPaths) {
153 processEvents();
154 }
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800155
156 if (refreshTopology) {
157 refreshTopologyTimer = new Timer();
158 refreshTopologyTimer.schedule(new TimerTask() {
159 @Override
160 public void run() {
Yuta HIGUCHIe0a87bb2014-01-07 13:58:01 -0800161 PerfMon pm = PerfMon.getInstance();
Yuta HIGUCHI8093ecb2014-01-08 16:38:21 -0800162 log.debug("[BEFORE] {}", topology);
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800163 long begin, end;
164 synchronized(topology) {
165 begin = System.nanoTime();
Yuta HIGUCHIe5ef3872014-01-07 12:35:59 -0800166 pm.read_whole_topology_start();
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800167 topology.readFromDatabase(flowManager.dbHandlerInner);
Yuta HIGUCHIe5ef3872014-01-07 12:35:59 -0800168 pm.read_whole_topology_end();
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800169 end = System.nanoTime();
170 }
Yuta HIGUCHIe5ef3872014-01-07 12:35:59 -0800171 // FIXME level raised for measurement. Was debug
Yuta HIGUCHI8093ecb2014-01-08 16:38:21 -0800172 log.error("[AFTER] {}", topology);
Yuta HIGUCHIe5ef3872014-01-07 12:35:59 -0800173 log.error("refresh takes : {}[us]", (end - begin) / 1000.0);
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800174 }
175 }, refreshTopologyDelay, refreshTopologyInterval);
176 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800177 }
178
179 /**
180 * Run the thread.
181 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800182 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800183 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800184 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800185 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700186
187 //
188 // The main loop
189 //
190 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
191 try {
192 while (true) {
193 EventEntry<?> eventEntry = networkEvents.take();
194 collection.add(eventEntry);
195 networkEvents.drainTo(collection);
196
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700197 //
198 // Demultiplex all events:
199 // - EventEntry<TopologyElement>
200 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700201 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700202 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700203 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800204 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700205 if (event.eventData() instanceof TopologyElement) {
206 EventEntry<TopologyElement> topologyEventEntry =
207 (EventEntry<TopologyElement>)event;
208 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800209 continue;
210 }
211
212 // FlowPath event
213 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700214 EventEntry<FlowPath> flowPathEventEntry =
215 (EventEntry<FlowPath>)event;
216 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800217 continue;
218 }
219
220 // FlowEntry event
221 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700222 EventEntry<FlowEntry> flowEntryEventEntry =
223 (EventEntry<FlowEntry>)event;
224 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800225 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700226 }
227 }
228 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700229
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700230 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800231 synchronized (allFlowPaths) {
232 processEvents();
233 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700234 }
235 } catch (Exception exception) {
236 log.debug("Exception processing Network Events: ", exception);
237 }
238 }
239
240 /**
241 * Process the events (if any)
242 */
243 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800244 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700245
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700246 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
247 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700248 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700249 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700250
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800251 processFlowPathEvents();
252 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800253 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800254 processFlowEntryEvents();
255
256 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800257 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800258 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800259 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800260 }
261
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800262 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800263 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800264
265 // Assign missing Flow Entry IDs
266 assignFlowEntryId(modifiedFlowEntries);
267
268 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800269 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800270 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800271 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
272 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800273
274 //
275 // Remove Flow Entries that were deleted
276 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800277 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800278 flowPath.dataPath().removeDeletedFlowEntries();
279
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800280 //
281 // Check if Flow Paths have been installed into all switches,
282 // and generate the appropriate events.
283 //
284 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
285
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800286 // Cleanup
287 topologyEvents.clear();
288 flowPathEvents.clear();
289 flowEntryEvents.clear();
290 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800291 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800292 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800293 checkIfInstalledFlowPaths.clear();
294 }
295
296 /**
297 * Check if Flow Paths have been installed into all switches,
298 * and generate the appropriate events.
299 *
300 * @param flowPaths the flowPaths to process.
301 */
302 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
303 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
304
305 Kryo kryo = kryoFactory.newKryo();
306
307 for (FlowPath flowPath : flowPaths) {
308 boolean isInstalled = true;
Jonathan Hart0444d932014-01-22 15:06:17 -0800309
310 if (flowPath.flowEntries().isEmpty()) {
311 continue;
312 }
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800313
314 //
315 // Check whether all Flow Entries have been installed
316 //
317 for (FlowEntry flowEntry : flowPath.flowEntries()) {
318 if (flowEntry.flowEntrySwitchState() !=
319 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
320 isInstalled = false;
321 break;
322 }
323 }
324
325 if (isInstalled) {
326 // Create a copy and add it to the list
327 FlowPath copyFlowPath = kryo.copy(flowPath);
328 installedFlowPaths.add(copyFlowPath);
329 }
330 }
331 kryoFactory.deleteKryo(kryo);
332
333 // Generate an event for the installed Flow Path.
334 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800335 }
336
337 /**
338 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800339 *
340 * @param modifiedFlowPaths the Flow Paths to process.
341 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800342 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800343 private Collection<FlowEntry> extractModifiedFlowEntries(
344 Collection<FlowPath> modifiedFlowPaths) {
345 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800346
347 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800348 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800349 for (FlowEntry flowEntry : flowPath.flowEntries()) {
350 if (flowEntry.flowEntrySwitchState() ==
351 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800352 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800353 }
354 }
355 }
356 return modifiedFlowEntries;
357 }
358
359 /**
360 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800361 *
362 * @param modifiedFlowEnries the collection of Flow Entries that need
363 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800364 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800365 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800366 if (modifiedFlowEntries.isEmpty())
367 return;
368
369 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
370
371 //
372 // Assign the Flow Entry ID only for Flow Entries for my switches
373 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800374 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800375 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
376 if (mySwitch == null)
377 continue;
378 if (! flowEntry.isValidFlowEntryId()) {
379 long id = flowManager.getNextFlowEntryId();
380 flowEntry.setFlowEntryId(new FlowEntryId(id));
381 }
382 }
383 }
384
385 /**
386 * Process the Flow Path events.
387 */
388 private void processFlowPathEvents() {
389 //
390 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700391 //
392 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
393 FlowPath flowPath = eventEntry.eventData();
394
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800395 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800396
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700397 switch (eventEntry.eventType()) {
398 case ENTRY_ADD: {
399 //
400 // Add a new Flow Path
401 //
402 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
403 //
404 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800405 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700406 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700407 }
408
409 switch (flowPath.flowPathType()) {
410 case FP_TYPE_SHORTEST_PATH:
411 //
412 // Reset the Data Path, in case it was set already, because
413 // we are going to recompute it anyway.
414 //
415 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800416 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
417 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700418 break;
419 case FP_TYPE_EXPLICIT_PATH:
420 //
421 // Mark all Flow Entries for installation in the switches.
422 //
423 for (FlowEntry flowEntry : flowPath.flowEntries()) {
424 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
425 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800426 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700427 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800428 case FP_TYPE_UNKNOWN:
429 log.error("FlowPath event with unknown type");
430 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700431 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800432 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700433
434 break;
435 }
436
437 case ENTRY_REMOVE: {
438 //
439 // Remove an existing Flow Path.
440 //
441 // Find the Flow Path, and mark the Flow and its Flow Entries
442 // for deletion.
443 //
444 FlowPath existingFlowPath =
445 allFlowPaths.get(flowPath.flowId().value());
446 if (existingFlowPath == null)
447 continue; // Nothing to do
448
449 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
450 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
451 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
452 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
453 }
454
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800455 // Remove the Flow Path from the internal state
456 Long key = existingFlowPath.flowId().value();
457 allFlowPaths.remove(key);
458 shouldRecomputeFlowPaths.remove(key);
459 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700460
461 break;
462 }
463 }
464 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800465 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700466
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800467 /**
468 * Process the Topology events.
469 */
470 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700471 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800472 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700473 //
474 boolean isTopologyModified = false;
475 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
476 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800477
478 log.debug("Topology Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800479 topologyElement);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800480
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700481 switch (eventEntry.eventType()) {
482 case ENTRY_ADD:
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800483 synchronized (topology) {
484 isTopologyModified |= topology.addTopologyElement(topologyElement);
485 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700486 break;
487 case ENTRY_REMOVE:
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800488 synchronized (topology) {
489 isTopologyModified |= topology.removeTopologyElement(topologyElement);
490 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700491 break;
492 }
493 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700494 if (isTopologyModified) {
495 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800496 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700497 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800498 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700499
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800500 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800501 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800502 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800503 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800504 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800505 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800506
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700507 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800508 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700509 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800510 if (! unmatchedFlowEntryAdd.isEmpty()) {
511 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
512 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800513 // log.debug("Processing Unmatched Flow Entry: {}",
514 // flowEntry.toString());
515
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800516 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800517 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800518 remainingUpdates.put(flowEntry.flowEntryId().value(),
519 flowEntry);
520 continue;
521 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800522 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
523 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800524 remainingUpdates.put(flowEntry.flowEntryId().value(),
525 flowEntry);
526 continue;
527 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800528 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
529 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
530 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700531 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800532 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700533 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800534 }
535
536 /**
537 * Process the Flow Entry events.
538 */
539 private void processFlowEntryEvents() {
540 FlowPath flowPath;
541 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700542
543 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800544 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700545 //
546 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
547 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800548
549 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800550 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800551
552 if ((! flowEntry.isValidFlowId()) ||
553 (! flowEntry.isValidFlowEntryId())) {
554 continue;
555 }
556
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700557 switch (eventEntry.eventType()) {
558 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800559 flowPath = allFlowPaths.get(flowEntry.flowId().value());
560 if (flowPath == null) {
561 // Flow Path not found: keep the entry for later matching
562 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
563 flowEntry);
564 break;
565 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800566 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
567 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800568 // Flow Entry not found: keep the entry for later matching
569 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
570 flowEntry);
571 break;
572 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800573 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
574 // Add the updated Flow Path to the list of updated paths
575 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
576 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700577 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800578
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700579 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800580 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
581 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800582 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800583 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800584
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800585 flowPath = allFlowPaths.get(flowEntry.flowId().value());
586 if (flowPath == null) {
587 // Flow Path not found: ignore the update
588 break;
589 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800590 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
591 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800592 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800593 break;
594 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800595 if (updateFlowEntryRemove(flowPath, localFlowEntry,
596 flowEntry)) {
597 // Add the updated Flow Path to the list of updated paths
598 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
599 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700600 break;
601 }
602 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700603 }
604
605 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800606 * Find a Flow Entry that should be updated because of an external
607 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700608 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800609 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800610 * @param newFlowEntry the FlowEntry with the new state.
611 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700612 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800613 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
614 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700615 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800616 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700617 //
618 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800619 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800620 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700621 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800622 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700623
624 //
625 // Local Flow Entry match found
626 //
627 if (localFlowEntry.isValidFlowEntryId()) {
628 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800629 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700630 //
631 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800632 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700633 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800634 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700635 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700636 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800637 return localFlowEntry;
638 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700639
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800640 return null; // Entry not found
641 }
642
643 /**
644 * Update a Flow Entry because of an external ENTRY_ADD event.
645 *
646 * @param flowPath the FlowPath for the Flow Entry to update.
647 * @param localFlowEntry the local Flow Entry to update.
648 * @param newFlowEntry the FlowEntry with the new state.
649 * @return true if the local Flow Entry was updated, otherwise false.
650 */
651 private boolean updateFlowEntryAdd(FlowPath flowPath,
652 FlowEntry localFlowEntry,
653 FlowEntry newFlowEntry) {
654 boolean updated = false;
655
656 if (localFlowEntry.flowEntryUserState() ==
657 FlowEntryUserState.FE_USER_DELETE) {
658 // Don't add-back a Flow Entry that is already deleted
659 return false;
660 }
661
662 if (! localFlowEntry.isValidFlowEntryId()) {
663 // Update the Flow Entry ID
664 FlowEntryId flowEntryId =
665 new FlowEntryId(newFlowEntry.flowEntryId().value());
666 localFlowEntry.setFlowEntryId(flowEntryId);
667 updated = true;
668 }
669
670 //
671 // Update the local Flow Entry, and keep state to check
672 // if the Flow Path has been installed.
673 //
674 if (localFlowEntry.flowEntryUserState() !=
675 newFlowEntry.flowEntryUserState()) {
676 localFlowEntry.setFlowEntryUserState(
677 newFlowEntry.flowEntryUserState());
678 updated = true;
679 }
680 if (localFlowEntry.flowEntrySwitchState() !=
681 newFlowEntry.flowEntrySwitchState()) {
682 localFlowEntry.setFlowEntrySwitchState(
683 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800684 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800685 updated = true;
686 }
687
688 return updated;
689 }
690
691 /**
692 * Find a Flow Entry that should be updated because of an external
693 * ENTRY_REMOVE event.
694 *
695 * @param flowPath the FlowPath for the Flow Entry to update.
696 * @param newFlowEntry the FlowEntry with the new state.
697 * @return the Flow Entry that should be updated if found, otherwise null.
698 */
699 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
700 FlowEntry newFlowEntry) {
701 //
702 // Iterate over all Flow Entries and find a match based on
703 // the Flow Entry ID.
704 //
705 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
706 if (! localFlowEntry.isValidFlowEntryId())
707 continue;
708 if (localFlowEntry.flowEntryId().value() !=
709 newFlowEntry.flowEntryId().value()) {
710 continue;
711 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800712 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700713 }
714
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800715 return null; // Entry not found
716 }
717
718 /**
719 * Update a Flow Entry because of an external ENTRY_REMOVE event.
720 *
721 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800722 * @param localFlowEntry the local Flow Entry to update.
723 * @param newFlowEntry the FlowEntry with the new state.
724 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800725 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800726 private boolean updateFlowEntryRemove(FlowPath flowPath,
727 FlowEntry localFlowEntry,
728 FlowEntry newFlowEntry) {
729 boolean updated = false;
730
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800731 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800732 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800733 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800734 if (localFlowEntry.flowEntryUserState() !=
735 newFlowEntry.flowEntryUserState()) {
736 localFlowEntry.setFlowEntryUserState(
737 newFlowEntry.flowEntryUserState());
738 updated = true;
739 }
740 if (localFlowEntry.flowEntrySwitchState() !=
741 newFlowEntry.flowEntrySwitchState()) {
742 localFlowEntry.setFlowEntrySwitchState(
743 newFlowEntry.flowEntrySwitchState());
744 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800745 }
746
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800747 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700748 }
749
750 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700751 * Recompute a Flow Path.
752 *
753 * @param flowPath the Flow Path to recompute.
754 * @return true if the recomputed Flow Path has changed, otherwise false.
755 */
756 private boolean recomputeFlowPath(FlowPath flowPath) {
757 boolean hasChanged = false;
758
759 //
760 // Test whether the Flow Path needs to be recomputed
761 //
762 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700763 case FP_TYPE_UNKNOWN:
764 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700765 case FP_TYPE_SHORTEST_PATH:
766 break;
767 case FP_TYPE_EXPLICIT_PATH:
768 return false; // An explicit path never changes
769 }
770
771 DataPath oldDataPath = flowPath.dataPath();
772
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700773 // Compute the new path
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800774 DataPath newDataPath;
775 synchronized (topology) {
776 newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700777 flowPath);
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800778 }
779
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700780 if (newDataPath == null) {
781 // We need the DataPath to compare the paths
782 newDataPath = new DataPath();
783 }
784 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
785
786 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700787 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700788 //
789 if (oldDataPath.flowEntries().size() !=
790 newDataPath.flowEntries().size()) {
791 hasChanged = true;
792 } else {
793 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
794 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
795 while (oldIter.hasNext() && newIter.hasNext()) {
796 FlowEntry oldFlowEntry = oldIter.next();
797 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700798 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
799 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700800 hasChanged = true;
801 break;
802 }
803 }
804 }
805 if (! hasChanged)
806 return hasChanged;
807
808 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700809 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700810 // - If a Flow Entry for a switch is in the old data path, but not
811 // in the new data path, then mark it for deletion.
812 // - If a Flow Entry for a switch is in the new data path, but not
813 // in the old data path, then mark it for addition.
814 // - If a Flow Entry for a switch is in both the old and the new
815 // data path, but it has changed, e.g., the incoming and/or outgoing
816 // port(s), then mark the old Flow Entry for deletion, and mark
817 // the new Flow Entry for addition.
818 // - If a Flow Entry for a switch is in both the old and the new
819 // data path, and it hasn't changed, then just keep it.
820 //
821 // NOTE: We use the Switch DPID of each entry to match the entries
822 //
823 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
824 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
825 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
826 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
827
828 // Prepare maps with the Flow Entries, so they are fast to lookup
829 for (FlowEntry flowEntry : oldDataPath.flowEntries())
830 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
831 for (FlowEntry flowEntry : newDataPath.flowEntries())
832 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
833
834 //
835 // Find the old Flow Entries that should be deleted
836 //
837 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
838 FlowEntry newFlowEntry =
839 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
840 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800841 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700842 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
843 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
844 deletedFlowEntries.add(oldFlowEntry);
845 }
846 }
847
848 //
849 // Find the new Flow Entries that should be added or updated
850 //
851 int idx = 0;
852 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
853 FlowEntry oldFlowEntry =
854 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
855
856 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700857 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
858 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700859 //
860 // Both Flow Entries are same
861 //
862 finalFlowEntries.add(oldFlowEntry);
863 idx++;
864 continue;
865 }
866
867 if (oldFlowEntry != null) {
868 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800869 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700870 //
871 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
872 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
873 deletedFlowEntries.add(oldFlowEntry);
874 }
875
876 //
877 // Add the new Flow Entry
878 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700879 //
880 // NOTE: Assign only the Flow ID.
881 // The Flow Entry ID is assigned later only for the Flow Entries
882 // this instance is responsible for.
883 //
884 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700885
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800886 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800887 // Copy the Flow timeouts
888 //
889 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
890 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
891
892 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800893 // Allocate the FlowEntryMatch by copying the default one
894 // from the FlowPath (if set).
895 //
896 FlowEntryMatch flowEntryMatch = null;
897 if (flowPath.flowEntryMatch() != null)
898 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
899 else
900 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700901 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800902
903 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700904 flowEntryMatch.enableInPort(newFlowEntry.inPort());
905
906 //
907 // Set the actions:
908 // If the first Flow Entry, copy the Flow Path actions to it.
909 //
910 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
911 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
912 FlowEntryActions flowActions =
913 new FlowEntryActions(flowPath.flowEntryActions());
914 for (FlowEntryAction action : flowActions.actions())
915 flowEntryActions.addAction(action);
916 }
917 idx++;
918
919 //
920 // Add the outgoing port output action
921 //
922 FlowEntryAction flowEntryAction = new FlowEntryAction();
923 flowEntryAction.setActionOutput(newFlowEntry.outPort());
924 flowEntryActions.addAction(flowEntryAction);
925
926 //
927 // Set the state of the new Flow Entry
928 //
929 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
930 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
931 finalFlowEntries.add(newFlowEntry);
932 }
933
934 //
935 // Replace the old Flow Entries with the new Flow Entries.
936 // Note that the Flow Entries that will be deleted are added at
937 // the end.
938 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800939 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700940 flowPath.dataPath().setFlowEntries(finalFlowEntries);
941
942 return hasChanged;
943 }
944
945 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700946 * Receive a notification that a Flow is added.
947 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700948 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700949 */
950 @Override
951 public void notificationRecvFlowAdded(FlowPath flowPath) {
952 EventEntry<FlowPath> eventEntry =
953 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
954 networkEvents.add(eventEntry);
955 }
956
957 /**
958 * Receive a notification that a Flow is removed.
959 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700960 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700961 */
962 @Override
963 public void notificationRecvFlowRemoved(FlowPath flowPath) {
964 EventEntry<FlowPath> eventEntry =
965 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
966 networkEvents.add(eventEntry);
967 }
968
969 /**
970 * Receive a notification that a Flow is updated.
971 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700972 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700973 */
974 @Override
975 public void notificationRecvFlowUpdated(FlowPath flowPath) {
976 // NOTE: The ADD and UPDATE events are processed in same way
977 EventEntry<FlowPath> eventEntry =
978 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
979 networkEvents.add(eventEntry);
980 }
981
982 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700983 * Receive a notification that a FlowEntry is added.
984 *
985 * @param flowEntry the FlowEntry that is added.
986 */
987 @Override
988 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
989 EventEntry<FlowEntry> eventEntry =
990 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
991 networkEvents.add(eventEntry);
992 }
993
994 /**
995 * Receive a notification that a FlowEntry is removed.
996 *
997 * @param flowEntry the FlowEntry that is removed.
998 */
999 @Override
1000 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
1001 EventEntry<FlowEntry> eventEntry =
1002 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1003 networkEvents.add(eventEntry);
1004 }
1005
1006 /**
1007 * Receive a notification that a FlowEntry is updated.
1008 *
1009 * @param flowEntry the FlowEntry that is updated.
1010 */
1011 @Override
1012 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1013 // NOTE: The ADD and UPDATE events are processed in same way
1014 EventEntry<FlowEntry> eventEntry =
1015 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1016 networkEvents.add(eventEntry);
1017 }
1018
1019 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001020 * Receive a notification that a Topology Element is added.
1021 *
1022 * @param topologyElement the Topology Element that is added.
1023 */
1024 @Override
1025 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1026 EventEntry<TopologyElement> eventEntry =
1027 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1028 networkEvents.add(eventEntry);
1029 }
1030
1031 /**
1032 * Receive a notification that a Topology Element is removed.
1033 *
1034 * @param topologyElement the Topology Element that is removed.
1035 */
1036 @Override
1037 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1038 EventEntry<TopologyElement> eventEntry =
1039 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1040 networkEvents.add(eventEntry);
1041 }
1042
1043 /**
1044 * Receive a notification that a Topology Element is updated.
1045 *
1046 * @param topologyElement the Topology Element that is updated.
1047 */
1048 @Override
1049 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1050 // NOTE: The ADD and UPDATE events are processed in same way
1051 EventEntry<TopologyElement> eventEntry =
1052 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1053 networkEvents.add(eventEntry);
1054 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001055
1056 /**
1057 * Get a sorted copy of all Flow Paths.
1058 *
1059 * @return a sorted copy of all Flow Paths.
1060 */
1061 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1062 SortedMap<Long, FlowPath> sortedFlowPaths =
1063 new TreeMap<Long, FlowPath>();
1064
1065 //
1066 // TODO: For now we use serialization/deserialization to create
1067 // a copy of each Flow Path. In the future, we should use proper
1068 // copy constructors.
1069 //
1070 Kryo kryo = kryoFactory.newKryo();
1071 synchronized (allFlowPaths) {
1072 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1073 FlowPath origFlowPath = entry.getValue();
1074 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1075 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1076 }
1077 }
1078 kryoFactory.deleteKryo(kryo);
1079
1080 return sortedFlowPaths;
1081 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001082}