blob: 0728f9a3bc05d56692da430c16ea9493dcc2d482 [file] [log] [blame]
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
2
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07003import java.util.ArrayList;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07004import java.util.Collection;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07005import java.util.HashMap;
6import java.util.Iterator;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07007import java.util.LinkedList;
8import java.util.List;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07009import java.util.Map;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
11import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.LinkedBlockingQueue;
14
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070016import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070017import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070019import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070020import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070021import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070022import net.onrc.onos.ofcontroller.util.FlowEntry;
23import net.onrc.onos.ofcontroller.util.FlowEntryAction;
24import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070025import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070026import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
27import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
28import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070029import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070030import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070031import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080032import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
33
34import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070035
36import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070040 * Class for FlowPath Maintenance.
41 * This class listens for FlowEvents to:
42 * - Maintain a local cache of the Network Topology.
43 * - Detect FlowPaths impacted by Topology change.
44 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070045 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070046class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070047 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070048 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070049
50 private FlowManager flowManager; // The Flow Manager to use
51 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070052 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080053 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070054
55 // The queue with Flow Path and Topology Element updates
56 private BlockingQueue<EventEntry<?>> networkEvents =
57 new LinkedBlockingQueue<EventEntry<?>>();
58
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070059 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070060 private List<EventEntry<TopologyElement>> topologyEvents =
61 new LinkedList<EventEntry<TopologyElement>>();
62 private List<EventEntry<FlowPath>> flowPathEvents =
63 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070064 private List<EventEntry<FlowEntry>> flowEntryEvents =
65 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -080066 private List<EventEntry<FlowId>> flowIdEvents =
67 new LinkedList<EventEntry<FlowId>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070068
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080069 // All internally computed Flow Paths
70 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
71
72 // The Flow Entries received as notifications with unmatched Flow Paths
73 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
74 new HashMap<Long, FlowEntry>();
75
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080076 //
77 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080078 // - The Flow Paths that should be recomputed
79 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080080 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080081 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080082 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
83 new HashMap<Long, FlowPath>();
84 private Map<Long, FlowPath> modifiedFlowPaths =
85 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080086 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
87 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080088
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070089 /**
90 * Constructor for a given Flow Manager and Datagrid Service.
91 *
92 * @param flowManager the Flow Manager to use.
93 * @param datagridService the Datagrid Service to use.
94 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070095 FlowEventHandler(FlowManager flowManager,
96 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070097 this.flowManager = flowManager;
98 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070099 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700100 }
101
102 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800103 * Get the network topology.
104 *
105 * @return the network topology.
106 */
107 protected Topology getTopology() { return this.topology; }
108
109 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800110 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700111 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800112 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700113 //
114 // Obtain the initial Topology state
115 //
116 Collection<TopologyElement> topologyElements =
117 datagridService.getAllTopologyElements();
118 for (TopologyElement topologyElement : topologyElements) {
119 EventEntry<TopologyElement> eventEntry =
120 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
121 topologyEvents.add(eventEntry);
122 }
123 //
124 // Obtain the initial Flow Path state
125 //
126 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
127 for (FlowPath flowPath : flowPaths) {
128 EventEntry<FlowPath> eventEntry =
129 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
130 flowPathEvents.add(eventEntry);
131 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700132 //
133 // Obtain the initial FlowEntry state
134 //
135 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
136 for (FlowEntry flowEntry : flowEntries) {
137 EventEntry<FlowEntry> eventEntry =
138 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
139 flowEntryEvents.add(eventEntry);
140 }
141
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800142 //
143 // Obtain the initial FlowId state
144 //
145 Collection<FlowId> flowIds = datagridService.getAllFlowIds();
146 for (FlowId flowId : flowIds) {
147 EventEntry<FlowId> eventEntry =
148 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
149 flowIdEvents.add(eventEntry);
150 }
151
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800152 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800153 synchronized (allFlowPaths) {
154 processEvents();
155 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800156 }
157
158 /**
159 * Run the thread.
160 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800161 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800162 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800163 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800164 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700165
166 //
167 // The main loop
168 //
169 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
170 try {
171 while (true) {
172 EventEntry<?> eventEntry = networkEvents.take();
173 collection.add(eventEntry);
174 networkEvents.drainTo(collection);
175
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700176 //
177 // Demultiplex all events:
178 // - EventEntry<TopologyElement>
179 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700180 // - EventEntry<FlowEntry>
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800181 // - EventEntry<FlowId>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700182 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700183 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800184 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700185 if (event.eventData() instanceof TopologyElement) {
186 EventEntry<TopologyElement> topologyEventEntry =
187 (EventEntry<TopologyElement>)event;
188 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800189 continue;
190 }
191
192 // FlowPath event
193 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700194 EventEntry<FlowPath> flowPathEventEntry =
195 (EventEntry<FlowPath>)event;
196 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800197 continue;
198 }
199
200 // FlowEntry event
201 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700202 EventEntry<FlowEntry> flowEntryEventEntry =
203 (EventEntry<FlowEntry>)event;
204 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800205 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700206 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800207
208 // FlowId event
209 if (event.eventData() instanceof FlowId) {
210 EventEntry<FlowId> flowIdEventEntry =
211 (EventEntry<FlowId>)event;
212 flowIdEvents.add(flowIdEventEntry);
213 continue;
214 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700215 }
216 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700217
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700218 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800219 synchronized (allFlowPaths) {
220 processEvents();
221 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700222 }
223 } catch (Exception exception) {
224 log.debug("Exception processing Network Events: ", exception);
225 }
226 }
227
228 /**
229 * Process the events (if any)
230 */
231 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800232 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700233
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700234 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
235 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700236 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700237 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700238
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800239 processFlowIdEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800240 processFlowPathEvents();
241 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800242 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800243 processFlowEntryEvents();
244
245 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800246 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800247 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800248 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800249 }
250
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800251 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800252 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800253
254 // Assign missing Flow Entry IDs
255 assignFlowEntryId(modifiedFlowEntries);
256
257 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800258 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800259 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800260 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
261 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800262
263 //
264 // Remove Flow Entries that were deleted
265 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800266 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800267 flowPath.dataPath().removeDeletedFlowEntries();
268
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800269 //
270 // Check if Flow Paths have been installed into all switches,
271 // and generate the appropriate events.
272 //
273 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
274
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800275 // Cleanup
276 topologyEvents.clear();
277 flowPathEvents.clear();
278 flowEntryEvents.clear();
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800279 flowIdEvents.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800280 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800281 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800282 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800283 checkIfInstalledFlowPaths.clear();
284 }
285
286 /**
287 * Check if Flow Paths have been installed into all switches,
288 * and generate the appropriate events.
289 *
290 * @param flowPaths the flowPaths to process.
291 */
292 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
293 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
294
295 Kryo kryo = kryoFactory.newKryo();
296
297 for (FlowPath flowPath : flowPaths) {
298 boolean isInstalled = true;
299
300 //
301 // Check whether all Flow Entries have been installed
302 //
303 for (FlowEntry flowEntry : flowPath.flowEntries()) {
304 if (flowEntry.flowEntrySwitchState() !=
305 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
306 isInstalled = false;
307 break;
308 }
309 }
310
311 if (isInstalled) {
312 // Create a copy and add it to the list
313 FlowPath copyFlowPath = kryo.copy(flowPath);
314 installedFlowPaths.add(copyFlowPath);
315 }
316 }
317 kryoFactory.deleteKryo(kryo);
318
319 // Generate an event for the installed Flow Path.
320 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800321 }
322
323 /**
324 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800325 *
326 * @param modifiedFlowPaths the Flow Paths to process.
327 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800328 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800329 private Collection<FlowEntry> extractModifiedFlowEntries(
330 Collection<FlowPath> modifiedFlowPaths) {
331 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800332
333 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800334 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800335 for (FlowEntry flowEntry : flowPath.flowEntries()) {
336 if (flowEntry.flowEntrySwitchState() ==
337 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800338 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800339 }
340 }
341 }
342 return modifiedFlowEntries;
343 }
344
345 /**
346 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800347 *
348 * @param modifiedFlowEnries the collection of Flow Entries that need
349 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800350 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800351 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800352 if (modifiedFlowEntries.isEmpty())
353 return;
354
355 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
356
357 //
358 // Assign the Flow Entry ID only for Flow Entries for my switches
359 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800360 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800361 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
362 if (mySwitch == null)
363 continue;
364 if (! flowEntry.isValidFlowEntryId()) {
365 long id = flowManager.getNextFlowEntryId();
366 flowEntry.setFlowEntryId(new FlowEntryId(id));
367 }
368 }
369 }
370
371 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800372 * Process the Flow ID events.
373 */
374 private void processFlowIdEvents() {
375 //
376 // Process all Flow ID events and update the appropriate state
377 //
378 for (EventEntry<FlowId> eventEntry : flowIdEvents) {
379 FlowId flowId = eventEntry.eventData();
380
381 log.debug("Flow ID Event: {} {}", eventEntry.eventType(), flowId);
382
383 switch (eventEntry.eventType()) {
384 case ENTRY_ADD: {
385 //
386 // Add a new Flow ID
387 //
388 // TODO: Implement it!
389
390 break;
391 }
392
393 case ENTRY_REMOVE: {
394 //
395 // Remove an existing Flow ID.
396 //
397 // TODO: Implement it!
398
399 break;
400 }
401 }
402 }
403 }
404
405
406 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800407 * Process the Flow Path events.
408 */
409 private void processFlowPathEvents() {
410 //
411 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700412 //
413 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
414 FlowPath flowPath = eventEntry.eventData();
415
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800416 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800417
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700418 switch (eventEntry.eventType()) {
419 case ENTRY_ADD: {
420 //
421 // Add a new Flow Path
422 //
423 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
424 //
425 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800426 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700427 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700428 }
429
430 switch (flowPath.flowPathType()) {
431 case FP_TYPE_SHORTEST_PATH:
432 //
433 // Reset the Data Path, in case it was set already, because
434 // we are going to recompute it anyway.
435 //
436 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800437 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
438 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700439 break;
440 case FP_TYPE_EXPLICIT_PATH:
441 //
442 // Mark all Flow Entries for installation in the switches.
443 //
444 for (FlowEntry flowEntry : flowPath.flowEntries()) {
445 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
446 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800447 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700448 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800449 case FP_TYPE_UNKNOWN:
450 log.error("FlowPath event with unknown type");
451 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700452 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800453 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700454
455 break;
456 }
457
458 case ENTRY_REMOVE: {
459 //
460 // Remove an existing Flow Path.
461 //
462 // Find the Flow Path, and mark the Flow and its Flow Entries
463 // for deletion.
464 //
465 FlowPath existingFlowPath =
466 allFlowPaths.get(flowPath.flowId().value());
467 if (existingFlowPath == null)
468 continue; // Nothing to do
469
470 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
471 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
472 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
473 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
474 }
475
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800476 // Remove the Flow Path from the internal state
477 Long key = existingFlowPath.flowId().value();
478 allFlowPaths.remove(key);
479 shouldRecomputeFlowPaths.remove(key);
480 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700481
482 break;
483 }
484 }
485 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800486 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700487
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800488 /**
489 * Process the Topology events.
490 */
491 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700492 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800493 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700494 //
495 boolean isTopologyModified = false;
496 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
497 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800498
499 log.debug("Topology Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800500 topologyElement);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800501
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700502 switch (eventEntry.eventType()) {
503 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700504 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700505 break;
506 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700507 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700508 break;
509 }
510 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700511 if (isTopologyModified) {
512 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800513 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700514 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800515 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700516
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800517 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800518 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800519 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800520 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800521 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800522 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800523
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700524 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800525 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700526 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800527 if (! unmatchedFlowEntryAdd.isEmpty()) {
528 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
529 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800530 // log.debug("Processing Unmatched Flow Entry: {}",
531 // flowEntry.toString());
532
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800533 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800534 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800535 remainingUpdates.put(flowEntry.flowEntryId().value(),
536 flowEntry);
537 continue;
538 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800539 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
540 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800541 remainingUpdates.put(flowEntry.flowEntryId().value(),
542 flowEntry);
543 continue;
544 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800545 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
546 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
547 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700548 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800549 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700550 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800551 }
552
553 /**
554 * Process the Flow Entry events.
555 */
556 private void processFlowEntryEvents() {
557 FlowPath flowPath;
558 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700559
560 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800561 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700562 //
563 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
564 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800565
566 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800567 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800568
569 if ((! flowEntry.isValidFlowId()) ||
570 (! flowEntry.isValidFlowEntryId())) {
571 continue;
572 }
573
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700574 switch (eventEntry.eventType()) {
575 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800576 flowPath = allFlowPaths.get(flowEntry.flowId().value());
577 if (flowPath == null) {
578 // Flow Path not found: keep the entry for later matching
579 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
580 flowEntry);
581 break;
582 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800583 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
584 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800585 // Flow Entry not found: keep the entry for later matching
586 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
587 flowEntry);
588 break;
589 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800590 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
591 // Add the updated Flow Path to the list of updated paths
592 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
593 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700594 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800595
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700596 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800597 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
598 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800599 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800600 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800601
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800602 flowPath = allFlowPaths.get(flowEntry.flowId().value());
603 if (flowPath == null) {
604 // Flow Path not found: ignore the update
605 break;
606 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800607 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
608 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800609 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800610 break;
611 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800612 if (updateFlowEntryRemove(flowPath, localFlowEntry,
613 flowEntry)) {
614 // Add the updated Flow Path to the list of updated paths
615 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
616 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700617 break;
618 }
619 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700620 }
621
622 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800623 * Find a Flow Entry that should be updated because of an external
624 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700625 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800626 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800627 * @param newFlowEntry the FlowEntry with the new state.
628 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700629 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800630 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
631 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700632 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800633 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700634 //
635 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800636 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800637 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700638 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800639 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700640
641 //
642 // Local Flow Entry match found
643 //
644 if (localFlowEntry.isValidFlowEntryId()) {
645 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800646 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700647 //
648 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800649 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700650 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800651 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700652 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700653 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800654 return localFlowEntry;
655 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700656
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800657 return null; // Entry not found
658 }
659
660 /**
661 * Update a Flow Entry because of an external ENTRY_ADD event.
662 *
663 * @param flowPath the FlowPath for the Flow Entry to update.
664 * @param localFlowEntry the local Flow Entry to update.
665 * @param newFlowEntry the FlowEntry with the new state.
666 * @return true if the local Flow Entry was updated, otherwise false.
667 */
668 private boolean updateFlowEntryAdd(FlowPath flowPath,
669 FlowEntry localFlowEntry,
670 FlowEntry newFlowEntry) {
671 boolean updated = false;
672
673 if (localFlowEntry.flowEntryUserState() ==
674 FlowEntryUserState.FE_USER_DELETE) {
675 // Don't add-back a Flow Entry that is already deleted
676 return false;
677 }
678
679 if (! localFlowEntry.isValidFlowEntryId()) {
680 // Update the Flow Entry ID
681 FlowEntryId flowEntryId =
682 new FlowEntryId(newFlowEntry.flowEntryId().value());
683 localFlowEntry.setFlowEntryId(flowEntryId);
684 updated = true;
685 }
686
687 //
688 // Update the local Flow Entry, and keep state to check
689 // if the Flow Path has been installed.
690 //
691 if (localFlowEntry.flowEntryUserState() !=
692 newFlowEntry.flowEntryUserState()) {
693 localFlowEntry.setFlowEntryUserState(
694 newFlowEntry.flowEntryUserState());
695 updated = true;
696 }
697 if (localFlowEntry.flowEntrySwitchState() !=
698 newFlowEntry.flowEntrySwitchState()) {
699 localFlowEntry.setFlowEntrySwitchState(
700 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800701 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800702 updated = true;
703 }
704
705 return updated;
706 }
707
708 /**
709 * Find a Flow Entry that should be updated because of an external
710 * ENTRY_REMOVE event.
711 *
712 * @param flowPath the FlowPath for the Flow Entry to update.
713 * @param newFlowEntry the FlowEntry with the new state.
714 * @return the Flow Entry that should be updated if found, otherwise null.
715 */
716 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
717 FlowEntry newFlowEntry) {
718 //
719 // Iterate over all Flow Entries and find a match based on
720 // the Flow Entry ID.
721 //
722 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
723 if (! localFlowEntry.isValidFlowEntryId())
724 continue;
725 if (localFlowEntry.flowEntryId().value() !=
726 newFlowEntry.flowEntryId().value()) {
727 continue;
728 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800729 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700730 }
731
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800732 return null; // Entry not found
733 }
734
735 /**
736 * Update a Flow Entry because of an external ENTRY_REMOVE event.
737 *
738 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800739 * @param localFlowEntry the local Flow Entry to update.
740 * @param newFlowEntry the FlowEntry with the new state.
741 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800742 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800743 private boolean updateFlowEntryRemove(FlowPath flowPath,
744 FlowEntry localFlowEntry,
745 FlowEntry newFlowEntry) {
746 boolean updated = false;
747
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800748 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800749 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800750 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800751 if (localFlowEntry.flowEntryUserState() !=
752 newFlowEntry.flowEntryUserState()) {
753 localFlowEntry.setFlowEntryUserState(
754 newFlowEntry.flowEntryUserState());
755 updated = true;
756 }
757 if (localFlowEntry.flowEntrySwitchState() !=
758 newFlowEntry.flowEntrySwitchState()) {
759 localFlowEntry.setFlowEntrySwitchState(
760 newFlowEntry.flowEntrySwitchState());
761 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800762 }
763
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800764 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700765 }
766
767 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700768 * Recompute a Flow Path.
769 *
770 * @param flowPath the Flow Path to recompute.
771 * @return true if the recomputed Flow Path has changed, otherwise false.
772 */
773 private boolean recomputeFlowPath(FlowPath flowPath) {
774 boolean hasChanged = false;
775
776 //
777 // Test whether the Flow Path needs to be recomputed
778 //
779 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700780 case FP_TYPE_UNKNOWN:
781 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700782 case FP_TYPE_SHORTEST_PATH:
783 break;
784 case FP_TYPE_EXPLICIT_PATH:
785 return false; // An explicit path never changes
786 }
787
788 DataPath oldDataPath = flowPath.dataPath();
789
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700790 // Compute the new path
791 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
792 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700793 if (newDataPath == null) {
794 // We need the DataPath to compare the paths
795 newDataPath = new DataPath();
796 }
797 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
798
799 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700800 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700801 //
802 if (oldDataPath.flowEntries().size() !=
803 newDataPath.flowEntries().size()) {
804 hasChanged = true;
805 } else {
806 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
807 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
808 while (oldIter.hasNext() && newIter.hasNext()) {
809 FlowEntry oldFlowEntry = oldIter.next();
810 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700811 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
812 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700813 hasChanged = true;
814 break;
815 }
816 }
817 }
818 if (! hasChanged)
819 return hasChanged;
820
821 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700822 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700823 // - If a Flow Entry for a switch is in the old data path, but not
824 // in the new data path, then mark it for deletion.
825 // - If a Flow Entry for a switch is in the new data path, but not
826 // in the old data path, then mark it for addition.
827 // - If a Flow Entry for a switch is in both the old and the new
828 // data path, but it has changed, e.g., the incoming and/or outgoing
829 // port(s), then mark the old Flow Entry for deletion, and mark
830 // the new Flow Entry for addition.
831 // - If a Flow Entry for a switch is in both the old and the new
832 // data path, and it hasn't changed, then just keep it.
833 //
834 // NOTE: We use the Switch DPID of each entry to match the entries
835 //
836 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
837 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
838 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
839 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
840
841 // Prepare maps with the Flow Entries, so they are fast to lookup
842 for (FlowEntry flowEntry : oldDataPath.flowEntries())
843 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
844 for (FlowEntry flowEntry : newDataPath.flowEntries())
845 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
846
847 //
848 // Find the old Flow Entries that should be deleted
849 //
850 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
851 FlowEntry newFlowEntry =
852 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
853 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800854 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700855 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
856 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
857 deletedFlowEntries.add(oldFlowEntry);
858 }
859 }
860
861 //
862 // Find the new Flow Entries that should be added or updated
863 //
864 int idx = 0;
865 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
866 FlowEntry oldFlowEntry =
867 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
868
869 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700870 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
871 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700872 //
873 // Both Flow Entries are same
874 //
875 finalFlowEntries.add(oldFlowEntry);
876 idx++;
877 continue;
878 }
879
880 if (oldFlowEntry != null) {
881 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800882 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700883 //
884 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
885 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
886 deletedFlowEntries.add(oldFlowEntry);
887 }
888
889 //
890 // Add the new Flow Entry
891 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700892 //
893 // NOTE: Assign only the Flow ID.
894 // The Flow Entry ID is assigned later only for the Flow Entries
895 // this instance is responsible for.
896 //
897 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700898
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800899 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -0800900 // Copy the Flow timeouts
901 //
902 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
903 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
904
905 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800906 // Allocate the FlowEntryMatch by copying the default one
907 // from the FlowPath (if set).
908 //
909 FlowEntryMatch flowEntryMatch = null;
910 if (flowPath.flowEntryMatch() != null)
911 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
912 else
913 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700914 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800915
916 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700917 flowEntryMatch.enableInPort(newFlowEntry.inPort());
918
919 //
920 // Set the actions:
921 // If the first Flow Entry, copy the Flow Path actions to it.
922 //
923 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
924 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
925 FlowEntryActions flowActions =
926 new FlowEntryActions(flowPath.flowEntryActions());
927 for (FlowEntryAction action : flowActions.actions())
928 flowEntryActions.addAction(action);
929 }
930 idx++;
931
932 //
933 // Add the outgoing port output action
934 //
935 FlowEntryAction flowEntryAction = new FlowEntryAction();
936 flowEntryAction.setActionOutput(newFlowEntry.outPort());
937 flowEntryActions.addAction(flowEntryAction);
938
939 //
940 // Set the state of the new Flow Entry
941 //
942 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
943 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
944 finalFlowEntries.add(newFlowEntry);
945 }
946
947 //
948 // Replace the old Flow Entries with the new Flow Entries.
949 // Note that the Flow Entries that will be deleted are added at
950 // the end.
951 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800952 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700953 flowPath.dataPath().setFlowEntries(finalFlowEntries);
954
955 return hasChanged;
956 }
957
958 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700959 * Receive a notification that a Flow is added.
960 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700961 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700962 */
963 @Override
964 public void notificationRecvFlowAdded(FlowPath flowPath) {
965 EventEntry<FlowPath> eventEntry =
966 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
967 networkEvents.add(eventEntry);
968 }
969
970 /**
971 * Receive a notification that a Flow is removed.
972 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700973 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700974 */
975 @Override
976 public void notificationRecvFlowRemoved(FlowPath flowPath) {
977 EventEntry<FlowPath> eventEntry =
978 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
979 networkEvents.add(eventEntry);
980 }
981
982 /**
983 * Receive a notification that a Flow is updated.
984 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700985 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700986 */
987 @Override
988 public void notificationRecvFlowUpdated(FlowPath flowPath) {
989 // NOTE: The ADD and UPDATE events are processed in same way
990 EventEntry<FlowPath> eventEntry =
991 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
992 networkEvents.add(eventEntry);
993 }
994
995 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700996 * Receive a notification that a FlowEntry is added.
997 *
998 * @param flowEntry the FlowEntry that is added.
999 */
1000 @Override
1001 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
1002 EventEntry<FlowEntry> eventEntry =
1003 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1004 networkEvents.add(eventEntry);
1005 }
1006
1007 /**
1008 * Receive a notification that a FlowEntry is removed.
1009 *
1010 * @param flowEntry the FlowEntry that is removed.
1011 */
1012 @Override
1013 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
1014 EventEntry<FlowEntry> eventEntry =
1015 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1016 networkEvents.add(eventEntry);
1017 }
1018
1019 /**
1020 * Receive a notification that a FlowEntry is updated.
1021 *
1022 * @param flowEntry the FlowEntry that is updated.
1023 */
1024 @Override
1025 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
1026 // NOTE: The ADD and UPDATE events are processed in same way
1027 EventEntry<FlowEntry> eventEntry =
1028 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1029 networkEvents.add(eventEntry);
1030 }
1031
1032 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001033 * Receive a notification that a FlowId is added.
1034 *
1035 * @param flowId the FlowId that is added.
1036 */
1037 @Override
1038 public void notificationRecvFlowIdAdded(FlowId flowId) {
1039 EventEntry<FlowId> eventEntry =
1040 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1041 networkEvents.add(eventEntry);
1042 }
1043
1044 /**
1045 * Receive a notification that a FlowId is removed.
1046 *
1047 * @param flowId the FlowId that is removed.
1048 */
1049 @Override
1050 public void notificationRecvFlowIdRemoved(FlowId flowId) {
1051 EventEntry<FlowId> eventEntry =
1052 new EventEntry<FlowId>(EventEntry.Type.ENTRY_REMOVE, flowId);
1053 networkEvents.add(eventEntry);
1054 }
1055
1056 /**
1057 * Receive a notification that a FlowId is updated.
1058 *
1059 * @param flowId the FlowId that is updated.
1060 */
1061 @Override
1062 public void notificationRecvFlowIdUpdated(FlowId flowId) {
1063 // NOTE: The ADD and UPDATE events are processed in same way
1064 EventEntry<FlowId> eventEntry =
1065 new EventEntry<FlowId>(EventEntry.Type.ENTRY_ADD, flowId);
1066 networkEvents.add(eventEntry);
1067 }
1068
1069 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001070 * Receive a notification that a Topology Element is added.
1071 *
1072 * @param topologyElement the Topology Element that is added.
1073 */
1074 @Override
1075 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1076 EventEntry<TopologyElement> eventEntry =
1077 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1078 networkEvents.add(eventEntry);
1079 }
1080
1081 /**
1082 * Receive a notification that a Topology Element is removed.
1083 *
1084 * @param topologyElement the Topology Element that is removed.
1085 */
1086 @Override
1087 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1088 EventEntry<TopologyElement> eventEntry =
1089 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1090 networkEvents.add(eventEntry);
1091 }
1092
1093 /**
1094 * Receive a notification that a Topology Element is updated.
1095 *
1096 * @param topologyElement the Topology Element that is updated.
1097 */
1098 @Override
1099 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1100 // NOTE: The ADD and UPDATE events are processed in same way
1101 EventEntry<TopologyElement> eventEntry =
1102 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1103 networkEvents.add(eventEntry);
1104 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001105
1106 /**
1107 * Get a sorted copy of all Flow Paths.
1108 *
1109 * @return a sorted copy of all Flow Paths.
1110 */
1111 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1112 SortedMap<Long, FlowPath> sortedFlowPaths =
1113 new TreeMap<Long, FlowPath>();
1114
1115 //
1116 // TODO: For now we use serialization/deserialization to create
1117 // a copy of each Flow Path. In the future, we should use proper
1118 // copy constructors.
1119 //
1120 Kryo kryo = kryoFactory.newKryo();
1121 synchronized (allFlowPaths) {
1122 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1123 FlowPath origFlowPath = entry.getValue();
1124 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1125 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1126 }
1127 }
1128 kryoFactory.deleteKryo(kryo);
1129
1130 return sortedFlowPaths;
1131 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001132}