blob: a9a6f0cd9f89695da15ec0c1acc09023967b7d60 [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
36import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070037
38import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070042 * Class for FlowPath Maintenance.
43 * This class listens for FlowEvents to:
44 * - Maintain a local cache of the Network Topology.
45 * - Detect FlowPaths impacted by Topology change.
46 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070047 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070048class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070049 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070050 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070051
Yuta HIGUCHId8c37242014-01-07 11:51:29 -080052 // Flag to refresh Topology object periodically
53 private final static boolean refreshTopology = true;
54 // Refresh delay(ms)
55 private final static long refreshTopologyDelay = 5000;
56 // Refresh interval(ms)
57 private final static long refreshTopologyInterval = 1000;
58 private Timer refreshTopologyTimer;
59
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070060 private FlowManager flowManager; // The Flow Manager to use
61 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070062 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080063 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070064
65 // The queue with Flow Path and Topology Element updates
66 private BlockingQueue<EventEntry<?>> networkEvents =
67 new LinkedBlockingQueue<EventEntry<?>>();
68
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070069 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070070 private List<EventEntry<TopologyElement>> topologyEvents =
71 new LinkedList<EventEntry<TopologyElement>>();
72 private List<EventEntry<FlowPath>> flowPathEvents =
73 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070074 private List<EventEntry<FlowEntry>> flowEntryEvents =
75 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070076
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080077 // All internally computed Flow Paths
78 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
79
80 // The Flow Entries received as notifications with unmatched Flow Paths
81 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
82 new HashMap<Long, FlowEntry>();
83
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080084 //
85 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080086 // - The Flow Paths that should be recomputed
87 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080088 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080089 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080090 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
91 new HashMap<Long, FlowPath>();
92 private Map<Long, FlowPath> modifiedFlowPaths =
93 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080094 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
95 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080096
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070097 /**
98 * Constructor for a given Flow Manager and Datagrid Service.
99 *
100 * @param flowManager the Flow Manager to use.
101 * @param datagridService the Datagrid Service to use.
102 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700103 FlowEventHandler(FlowManager flowManager,
104 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700105 this.flowManager = flowManager;
106 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700107 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700108 }
109
110 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800111 * Get the network topology.
112 *
113 * @return the network topology.
114 */
115 protected Topology getTopology() { return this.topology; }
116
117 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800118 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700119 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800120 private void startup() {
Pavlin 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 Radoslavovfb94edc2013-11-04 16:29:40 -0800150 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800151 synchronized (allFlowPaths) {
152 processEvents();
153 }
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800154
155 if (refreshTopology) {
156 refreshTopologyTimer = new Timer();
157 refreshTopologyTimer.schedule(new TimerTask() {
158 @Override
159 public void run() {
160 log.debug("[BEFORE] {}", topology.toString());
161 long begin, end;
162 synchronized(topology) {
163 begin = System.nanoTime();
164 topology.readFromDatabase(flowManager.dbHandlerInner);
165 end = System.nanoTime();
166 }
167 log.debug("[AFTER] {}", topology.toString());
168 log.debug("refresh takes : {}[us]", (end - begin) / 1000.0);
169 }
170 }, refreshTopologyDelay, refreshTopologyInterval);
171 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800172 }
173
174 /**
175 * Run the thread.
176 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800177 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800178 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800179 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800180 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700181
182 //
183 // The main loop
184 //
185 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
186 try {
187 while (true) {
188 EventEntry<?> eventEntry = networkEvents.take();
189 collection.add(eventEntry);
190 networkEvents.drainTo(collection);
191
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700192 //
193 // Demultiplex all events:
194 // - EventEntry<TopologyElement>
195 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700196 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700197 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700198 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800199 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700200 if (event.eventData() instanceof TopologyElement) {
201 EventEntry<TopologyElement> topologyEventEntry =
202 (EventEntry<TopologyElement>)event;
203 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800204 continue;
205 }
206
207 // FlowPath event
208 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700209 EventEntry<FlowPath> flowPathEventEntry =
210 (EventEntry<FlowPath>)event;
211 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800212 continue;
213 }
214
215 // FlowEntry event
216 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700217 EventEntry<FlowEntry> flowEntryEventEntry =
218 (EventEntry<FlowEntry>)event;
219 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800220 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700221 }
222 }
223 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700224
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700225 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800226 synchronized (allFlowPaths) {
227 processEvents();
228 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700229 }
230 } catch (Exception exception) {
231 log.debug("Exception processing Network Events: ", exception);
232 }
233 }
234
235 /**
236 * Process the events (if any)
237 */
238 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800239 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700240
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700241 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
242 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700243 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700244 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700245
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800246 processFlowPathEvents();
247 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800248 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800249 processFlowEntryEvents();
250
251 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800252 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800253 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800254 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800255 }
256
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800257 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800258 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800259
260 // Assign missing Flow Entry IDs
261 assignFlowEntryId(modifiedFlowEntries);
262
263 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800264 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800265 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800266 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
267 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800268
269 //
270 // Remove Flow Entries that were deleted
271 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800272 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800273 flowPath.dataPath().removeDeletedFlowEntries();
274
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800275 //
276 // Check if Flow Paths have been installed into all switches,
277 // and generate the appropriate events.
278 //
279 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
280
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800281 // Cleanup
282 topologyEvents.clear();
283 flowPathEvents.clear();
284 flowEntryEvents.clear();
285 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800286 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800287 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800288 checkIfInstalledFlowPaths.clear();
289 }
290
291 /**
292 * Check if Flow Paths have been installed into all switches,
293 * and generate the appropriate events.
294 *
295 * @param flowPaths the flowPaths to process.
296 */
297 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
298 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
299
300 Kryo kryo = kryoFactory.newKryo();
301
302 for (FlowPath flowPath : flowPaths) {
303 boolean isInstalled = true;
304
305 //
306 // Check whether all Flow Entries have been installed
307 //
308 for (FlowEntry flowEntry : flowPath.flowEntries()) {
309 if (flowEntry.flowEntrySwitchState() !=
310 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
311 isInstalled = false;
312 break;
313 }
314 }
315
316 if (isInstalled) {
317 // Create a copy and add it to the list
318 FlowPath copyFlowPath = kryo.copy(flowPath);
319 installedFlowPaths.add(copyFlowPath);
320 }
321 }
322 kryoFactory.deleteKryo(kryo);
323
324 // Generate an event for the installed Flow Path.
325 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800326 }
327
328 /**
329 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800330 *
331 * @param modifiedFlowPaths the Flow Paths to process.
332 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800333 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800334 private Collection<FlowEntry> extractModifiedFlowEntries(
335 Collection<FlowPath> modifiedFlowPaths) {
336 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800337
338 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800339 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800340 for (FlowEntry flowEntry : flowPath.flowEntries()) {
341 if (flowEntry.flowEntrySwitchState() ==
342 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800343 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800344 }
345 }
346 }
347 return modifiedFlowEntries;
348 }
349
350 /**
351 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800352 *
353 * @param modifiedFlowEnries the collection of Flow Entries that need
354 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800355 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800356 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800357 if (modifiedFlowEntries.isEmpty())
358 return;
359
360 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
361
362 //
363 // Assign the Flow Entry ID only for Flow Entries for my switches
364 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800365 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800366 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
367 if (mySwitch == null)
368 continue;
369 if (! flowEntry.isValidFlowEntryId()) {
370 long id = flowManager.getNextFlowEntryId();
371 flowEntry.setFlowEntryId(new FlowEntryId(id));
372 }
373 }
374 }
375
376 /**
377 * Process the Flow Path events.
378 */
379 private void processFlowPathEvents() {
380 //
381 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700382 //
383 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
384 FlowPath flowPath = eventEntry.eventData();
385
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800386 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800387
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700388 switch (eventEntry.eventType()) {
389 case ENTRY_ADD: {
390 //
391 // Add a new Flow Path
392 //
393 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
394 //
395 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800396 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700397 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700398 }
399
400 switch (flowPath.flowPathType()) {
401 case FP_TYPE_SHORTEST_PATH:
402 //
403 // Reset the Data Path, in case it was set already, because
404 // we are going to recompute it anyway.
405 //
406 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800407 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
408 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700409 break;
410 case FP_TYPE_EXPLICIT_PATH:
411 //
412 // Mark all Flow Entries for installation in the switches.
413 //
414 for (FlowEntry flowEntry : flowPath.flowEntries()) {
415 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
416 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800417 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700418 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800419 case FP_TYPE_UNKNOWN:
420 log.error("FlowPath event with unknown type");
421 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700422 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800423 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700424
425 break;
426 }
427
428 case ENTRY_REMOVE: {
429 //
430 // Remove an existing Flow Path.
431 //
432 // Find the Flow Path, and mark the Flow and its Flow Entries
433 // for deletion.
434 //
435 FlowPath existingFlowPath =
436 allFlowPaths.get(flowPath.flowId().value());
437 if (existingFlowPath == null)
438 continue; // Nothing to do
439
440 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
441 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
442 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
443 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
444 }
445
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800446 // Remove the Flow Path from the internal state
447 Long key = existingFlowPath.flowId().value();
448 allFlowPaths.remove(key);
449 shouldRecomputeFlowPaths.remove(key);
450 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700451
452 break;
453 }
454 }
455 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800456 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700457
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800458 /**
459 * Process the Topology events.
460 */
461 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700462 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800463 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700464 //
465 boolean isTopologyModified = false;
466 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
467 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800468
469 log.debug("Topology Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800470 topologyElement);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800471
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700472 switch (eventEntry.eventType()) {
473 case ENTRY_ADD:
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800474 synchronized (topology) {
475 isTopologyModified |= topology.addTopologyElement(topologyElement);
476 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700477 break;
478 case ENTRY_REMOVE:
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800479 synchronized (topology) {
480 isTopologyModified |= topology.removeTopologyElement(topologyElement);
481 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700482 break;
483 }
484 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700485 if (isTopologyModified) {
486 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800487 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700488 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800489 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700490
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800491 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800492 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800493 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800494 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800495 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800496 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800497
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700498 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800499 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700500 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800501 if (! unmatchedFlowEntryAdd.isEmpty()) {
502 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
503 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800504 // log.debug("Processing Unmatched Flow Entry: {}",
505 // flowEntry.toString());
506
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800507 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800508 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800509 remainingUpdates.put(flowEntry.flowEntryId().value(),
510 flowEntry);
511 continue;
512 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800513 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
514 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800515 remainingUpdates.put(flowEntry.flowEntryId().value(),
516 flowEntry);
517 continue;
518 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800519 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
520 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
521 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700522 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800523 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700524 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800525 }
526
527 /**
528 * Process the Flow Entry events.
529 */
530 private void processFlowEntryEvents() {
531 FlowPath flowPath;
532 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700533
534 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800535 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700536 //
537 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
538 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800539
540 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800541 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800542
543 if ((! flowEntry.isValidFlowId()) ||
544 (! flowEntry.isValidFlowEntryId())) {
545 continue;
546 }
547
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700548 switch (eventEntry.eventType()) {
549 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800550 flowPath = allFlowPaths.get(flowEntry.flowId().value());
551 if (flowPath == null) {
552 // Flow Path not found: keep the entry for later matching
553 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
554 flowEntry);
555 break;
556 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800557 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
558 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800559 // Flow Entry not found: keep the entry for later matching
560 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
561 flowEntry);
562 break;
563 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800564 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
565 // Add the updated Flow Path to the list of updated paths
566 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
567 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700568 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800569
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700570 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800571 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
572 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800573 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800574 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800575
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800576 flowPath = allFlowPaths.get(flowEntry.flowId().value());
577 if (flowPath == null) {
578 // Flow Path not found: ignore the update
579 break;
580 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800581 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
582 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800583 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800584 break;
585 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800586 if (updateFlowEntryRemove(flowPath, localFlowEntry,
587 flowEntry)) {
588 // Add the updated Flow Path to the list of updated paths
589 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
590 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700591 break;
592 }
593 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700594 }
595
596 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800597 * Find a Flow Entry that should be updated because of an external
598 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700599 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800600 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800601 * @param newFlowEntry the FlowEntry with the new state.
602 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700603 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800604 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
605 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700606 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800607 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700608 //
609 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800610 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800611 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700612 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800613 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700614
615 //
616 // Local Flow Entry match found
617 //
618 if (localFlowEntry.isValidFlowEntryId()) {
619 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800620 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700621 //
622 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800623 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700624 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800625 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700626 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700627 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800628 return localFlowEntry;
629 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700630
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800631 return null; // Entry not found
632 }
633
634 /**
635 * Update a Flow Entry because of an external ENTRY_ADD event.
636 *
637 * @param flowPath the FlowPath for the Flow Entry to update.
638 * @param localFlowEntry the local Flow Entry to update.
639 * @param newFlowEntry the FlowEntry with the new state.
640 * @return true if the local Flow Entry was updated, otherwise false.
641 */
642 private boolean updateFlowEntryAdd(FlowPath flowPath,
643 FlowEntry localFlowEntry,
644 FlowEntry newFlowEntry) {
645 boolean updated = false;
646
647 if (localFlowEntry.flowEntryUserState() ==
648 FlowEntryUserState.FE_USER_DELETE) {
649 // Don't add-back a Flow Entry that is already deleted
650 return false;
651 }
652
653 if (! localFlowEntry.isValidFlowEntryId()) {
654 // Update the Flow Entry ID
655 FlowEntryId flowEntryId =
656 new FlowEntryId(newFlowEntry.flowEntryId().value());
657 localFlowEntry.setFlowEntryId(flowEntryId);
658 updated = true;
659 }
660
661 //
662 // Update the local Flow Entry, and keep state to check
663 // if the Flow Path has been installed.
664 //
665 if (localFlowEntry.flowEntryUserState() !=
666 newFlowEntry.flowEntryUserState()) {
667 localFlowEntry.setFlowEntryUserState(
668 newFlowEntry.flowEntryUserState());
669 updated = true;
670 }
671 if (localFlowEntry.flowEntrySwitchState() !=
672 newFlowEntry.flowEntrySwitchState()) {
673 localFlowEntry.setFlowEntrySwitchState(
674 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800675 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800676 updated = true;
677 }
678
679 return updated;
680 }
681
682 /**
683 * Find a Flow Entry that should be updated because of an external
684 * ENTRY_REMOVE event.
685 *
686 * @param flowPath the FlowPath for the Flow Entry to update.
687 * @param newFlowEntry the FlowEntry with the new state.
688 * @return the Flow Entry that should be updated if found, otherwise null.
689 */
690 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
691 FlowEntry newFlowEntry) {
692 //
693 // Iterate over all Flow Entries and find a match based on
694 // the Flow Entry ID.
695 //
696 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
697 if (! localFlowEntry.isValidFlowEntryId())
698 continue;
699 if (localFlowEntry.flowEntryId().value() !=
700 newFlowEntry.flowEntryId().value()) {
701 continue;
702 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800703 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700704 }
705
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800706 return null; // Entry not found
707 }
708
709 /**
710 * Update a Flow Entry because of an external ENTRY_REMOVE event.
711 *
712 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800713 * @param localFlowEntry the local Flow Entry to update.
714 * @param newFlowEntry the FlowEntry with the new state.
715 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800716 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800717 private boolean updateFlowEntryRemove(FlowPath flowPath,
718 FlowEntry localFlowEntry,
719 FlowEntry newFlowEntry) {
720 boolean updated = false;
721
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800722 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800723 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800724 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800725 if (localFlowEntry.flowEntryUserState() !=
726 newFlowEntry.flowEntryUserState()) {
727 localFlowEntry.setFlowEntryUserState(
728 newFlowEntry.flowEntryUserState());
729 updated = true;
730 }
731 if (localFlowEntry.flowEntrySwitchState() !=
732 newFlowEntry.flowEntrySwitchState()) {
733 localFlowEntry.setFlowEntrySwitchState(
734 newFlowEntry.flowEntrySwitchState());
735 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800736 }
737
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800738 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700739 }
740
741 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700742 * Recompute a Flow Path.
743 *
744 * @param flowPath the Flow Path to recompute.
745 * @return true if the recomputed Flow Path has changed, otherwise false.
746 */
747 private boolean recomputeFlowPath(FlowPath flowPath) {
748 boolean hasChanged = false;
749
750 //
751 // Test whether the Flow Path needs to be recomputed
752 //
753 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700754 case FP_TYPE_UNKNOWN:
755 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700756 case FP_TYPE_SHORTEST_PATH:
757 break;
758 case FP_TYPE_EXPLICIT_PATH:
759 return false; // An explicit path never changes
760 }
761
762 DataPath oldDataPath = flowPath.dataPath();
763
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700764 // Compute the new path
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800765 DataPath newDataPath;
766 synchronized (topology) {
767 newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700768 flowPath);
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800769 }
770
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700771 if (newDataPath == null) {
772 // We need the DataPath to compare the paths
773 newDataPath = new DataPath();
774 }
775 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
776
777 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700778 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700779 //
780 if (oldDataPath.flowEntries().size() !=
781 newDataPath.flowEntries().size()) {
782 hasChanged = true;
783 } else {
784 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
785 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
786 while (oldIter.hasNext() && newIter.hasNext()) {
787 FlowEntry oldFlowEntry = oldIter.next();
788 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700789 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
790 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700791 hasChanged = true;
792 break;
793 }
794 }
795 }
796 if (! hasChanged)
797 return hasChanged;
798
799 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700800 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700801 // - If a Flow Entry for a switch is in the old data path, but not
802 // in the new data path, then mark it for deletion.
803 // - If a Flow Entry for a switch is in the new data path, but not
804 // in the old data path, then mark it for addition.
805 // - If a Flow Entry for a switch is in both the old and the new
806 // data path, but it has changed, e.g., the incoming and/or outgoing
807 // port(s), then mark the old Flow Entry for deletion, and mark
808 // the new Flow Entry for addition.
809 // - If a Flow Entry for a switch is in both the old and the new
810 // data path, and it hasn't changed, then just keep it.
811 //
812 // NOTE: We use the Switch DPID of each entry to match the entries
813 //
814 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
815 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
816 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
817 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
818
819 // Prepare maps with the Flow Entries, so they are fast to lookup
820 for (FlowEntry flowEntry : oldDataPath.flowEntries())
821 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
822 for (FlowEntry flowEntry : newDataPath.flowEntries())
823 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
824
825 //
826 // Find the old Flow Entries that should be deleted
827 //
828 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
829 FlowEntry newFlowEntry =
830 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
831 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800832 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700833 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
834 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
835 deletedFlowEntries.add(oldFlowEntry);
836 }
837 }
838
839 //
840 // Find the new Flow Entries that should be added or updated
841 //
842 int idx = 0;
843 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
844 FlowEntry oldFlowEntry =
845 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
846
847 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700848 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
849 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700850 //
851 // Both Flow Entries are same
852 //
853 finalFlowEntries.add(oldFlowEntry);
854 idx++;
855 continue;
856 }
857
858 if (oldFlowEntry != null) {
859 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800860 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700861 //
862 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
863 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
864 deletedFlowEntries.add(oldFlowEntry);
865 }
866
867 //
868 // Add the new Flow Entry
869 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700870 //
871 // NOTE: Assign only the Flow ID.
872 // The Flow Entry ID is assigned later only for the Flow Entries
873 // this instance is responsible for.
874 //
875 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700876
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800877 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800878 // Copy the Flow timeouts
879 //
880 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
881 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
882
883 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800884 // Allocate the FlowEntryMatch by copying the default one
885 // from the FlowPath (if set).
886 //
887 FlowEntryMatch flowEntryMatch = null;
888 if (flowPath.flowEntryMatch() != null)
889 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
890 else
891 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700892 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800893
894 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700895 flowEntryMatch.enableInPort(newFlowEntry.inPort());
896
897 //
898 // Set the actions:
899 // If the first Flow Entry, copy the Flow Path actions to it.
900 //
901 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
902 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
903 FlowEntryActions flowActions =
904 new FlowEntryActions(flowPath.flowEntryActions());
905 for (FlowEntryAction action : flowActions.actions())
906 flowEntryActions.addAction(action);
907 }
908 idx++;
909
910 //
911 // Add the outgoing port output action
912 //
913 FlowEntryAction flowEntryAction = new FlowEntryAction();
914 flowEntryAction.setActionOutput(newFlowEntry.outPort());
915 flowEntryActions.addAction(flowEntryAction);
916
917 //
918 // Set the state of the new Flow Entry
919 //
920 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
921 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
922 finalFlowEntries.add(newFlowEntry);
923 }
924
925 //
926 // Replace the old Flow Entries with the new Flow Entries.
927 // Note that the Flow Entries that will be deleted are added at
928 // the end.
929 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800930 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700931 flowPath.dataPath().setFlowEntries(finalFlowEntries);
932
933 return hasChanged;
934 }
935
936 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700937 * Receive a notification that a Flow is added.
938 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700939 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700940 */
941 @Override
942 public void notificationRecvFlowAdded(FlowPath flowPath) {
943 EventEntry<FlowPath> eventEntry =
944 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
945 networkEvents.add(eventEntry);
946 }
947
948 /**
949 * Receive a notification that a Flow is removed.
950 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700951 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700952 */
953 @Override
954 public void notificationRecvFlowRemoved(FlowPath flowPath) {
955 EventEntry<FlowPath> eventEntry =
956 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
957 networkEvents.add(eventEntry);
958 }
959
960 /**
961 * Receive a notification that a Flow is updated.
962 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700963 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700964 */
965 @Override
966 public void notificationRecvFlowUpdated(FlowPath flowPath) {
967 // NOTE: The ADD and UPDATE events are processed in same way
968 EventEntry<FlowPath> eventEntry =
969 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
970 networkEvents.add(eventEntry);
971 }
972
973 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700974 * Receive a notification that a FlowEntry is added.
975 *
976 * @param flowEntry the FlowEntry that is added.
977 */
978 @Override
979 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
980 EventEntry<FlowEntry> eventEntry =
981 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
982 networkEvents.add(eventEntry);
983 }
984
985 /**
986 * Receive a notification that a FlowEntry is removed.
987 *
988 * @param flowEntry the FlowEntry that is removed.
989 */
990 @Override
991 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
992 EventEntry<FlowEntry> eventEntry =
993 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
994 networkEvents.add(eventEntry);
995 }
996
997 /**
998 * Receive a notification that a FlowEntry is updated.
999 *
1000 * @param flowEntry the FlowEntry that is updated.
1001 */
1002 @Override
1003 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1004 // NOTE: The ADD and UPDATE events are processed in same way
1005 EventEntry<FlowEntry> eventEntry =
1006 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1007 networkEvents.add(eventEntry);
1008 }
1009
1010 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001011 * Receive a notification that a Topology Element is added.
1012 *
1013 * @param topologyElement the Topology Element that is added.
1014 */
1015 @Override
1016 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1017 EventEntry<TopologyElement> eventEntry =
1018 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1019 networkEvents.add(eventEntry);
1020 }
1021
1022 /**
1023 * Receive a notification that a Topology Element is removed.
1024 *
1025 * @param topologyElement the Topology Element that is removed.
1026 */
1027 @Override
1028 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1029 EventEntry<TopologyElement> eventEntry =
1030 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1031 networkEvents.add(eventEntry);
1032 }
1033
1034 /**
1035 * Receive a notification that a Topology Element is updated.
1036 *
1037 * @param topologyElement the Topology Element that is updated.
1038 */
1039 @Override
1040 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1041 // NOTE: The ADD and UPDATE events are processed in same way
1042 EventEntry<TopologyElement> eventEntry =
1043 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1044 networkEvents.add(eventEntry);
1045 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001046
1047 /**
1048 * Get a sorted copy of all Flow Paths.
1049 *
1050 * @return a sorted copy of all Flow Paths.
1051 */
1052 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1053 SortedMap<Long, FlowPath> sortedFlowPaths =
1054 new TreeMap<Long, FlowPath>();
1055
1056 //
1057 // TODO: For now we use serialization/deserialization to create
1058 // a copy of each Flow Path. In the future, we should use proper
1059 // copy constructors.
1060 //
1061 Kryo kryo = kryoFactory.newKryo();
1062 synchronized (allFlowPaths) {
1063 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1064 FlowPath origFlowPath = entry.getValue();
1065 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1066 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1067 }
1068 }
1069 kryoFactory.deleteKryo(kryo);
1070
1071 return sortedFlowPaths;
1072 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001073}