blob: 662e81b2e1eb55a84edf7adcf61dfb431d0f2051 [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 Radoslavovcc757162014-01-10 16:26:38 -080016import net.floodlightcontroller.core.IOFSwitchListener;
17
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.datagrid.IDatagridService;
Naoki Shiota0abe38d2014-01-07 15:31:22 -080019import net.onrc.onos.graph.GraphDBOperation;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070020import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070021import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070022import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070023import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080024import net.onrc.onos.ofcontroller.util.Dpid;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070025import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070026import net.onrc.onos.ofcontroller.util.FlowEntry;
27import net.onrc.onos.ofcontroller.util.FlowEntryAction;
28import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070029import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070030import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
31import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
32import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070033import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070034import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070035import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080036import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080037import net.onrc.onos.ofcontroller.util.Port;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080038import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
39
40import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070041
42import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
45/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070046 * Class for FlowPath Maintenance.
47 * This class listens for FlowEvents to:
48 * - Maintain a local cache of the Network Topology.
49 * - Detect FlowPaths impacted by Topology change.
50 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070051 */
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080052class FlowEventHandler extends Thread implements IFlowEventHandlerService,
53 IOFSwitchListener {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080054
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080055 private boolean enableOnrc2014MeasurementsFlows = true;
56 private boolean enableOnrc2014MeasurementsTopology = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080057
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070058 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070059 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080060
Naoki Shiota0abe38d2014-01-07 15:31:22 -080061 private GraphDBOperation dbHandler;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -080062
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070063 private FlowManager flowManager; // The Flow Manager to use
64 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070065 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080066 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070067
68 // The queue with Flow Path and Topology Element updates
69 private BlockingQueue<EventEntry<?>> networkEvents =
70 new LinkedBlockingQueue<EventEntry<?>>();
71
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070072 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070073 private List<EventEntry<TopologyElement>> topologyEvents =
74 new LinkedList<EventEntry<TopologyElement>>();
75 private List<EventEntry<FlowPath>> flowPathEvents =
76 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070077 private List<EventEntry<FlowEntry>> flowEntryEvents =
78 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2194d112014-01-10 13:36:00 -080079 private List<EventEntry<Pair<FlowId, Dpid>>> flowIdEvents =
80 new LinkedList<EventEntry<Pair<FlowId, Dpid>>>();
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080081 private List<EventEntry<Pair<FlowEntryId, Dpid>>> flowEntryIdEvents =
82 new LinkedList<EventEntry<Pair<FlowEntryId, Dpid>>>();
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080083 private List<EventEntry<Dpid>> switchDpidEvents =
84 new LinkedList<EventEntry<Dpid>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070085
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080086 // All internally computed Flow Paths
87 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
88
89 // The Flow Entries received as notifications with unmatched Flow Paths
90 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
91 new HashMap<Long, FlowEntry>();
92
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080093 //
94 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080095 // - The Flow Paths that should be recomputed
96 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080097 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080098 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080099 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
100 new HashMap<Long, FlowPath>();
101 private Map<Long, FlowPath> modifiedFlowPaths =
102 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800103 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
104 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800105
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700106 /**
107 * Constructor for a given Flow Manager and Datagrid Service.
108 *
109 * @param flowManager the Flow Manager to use.
110 * @param datagridService the Datagrid Service to use.
111 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700112 FlowEventHandler(FlowManager flowManager,
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800113 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700114 this.flowManager = flowManager;
115 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700116 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700117 }
118
119 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800120 * Get the network topology.
121 *
122 * @return the network topology.
123 */
124 protected Topology getTopology() { return this.topology; }
125
126 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800127 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700128 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800129 private void startup() {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800130 this.dbHandler = new GraphDBOperation("");
131
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700132 //
133 // Obtain the initial Topology state
134 //
135 Collection<TopologyElement> topologyElements =
136 datagridService.getAllTopologyElements();
137 for (TopologyElement topologyElement : topologyElements) {
138 EventEntry<TopologyElement> eventEntry =
139 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
140 topologyEvents.add(eventEntry);
141 }
142 //
143 // Obtain the initial Flow Path state
144 //
145 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
146 for (FlowPath flowPath : flowPaths) {
147 EventEntry<FlowPath> eventEntry =
148 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
149 flowPathEvents.add(eventEntry);
150 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700151 //
152 // Obtain the initial FlowEntry state
153 //
154 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
155 for (FlowEntry flowEntry : flowEntries) {
156 EventEntry<FlowEntry> eventEntry =
157 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
158 flowEntryEvents.add(eventEntry);
159 }
160
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800161 //
162 // Obtain the initial FlowId state
163 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800164 Collection<Pair<FlowId, Dpid>> flowIds =
165 datagridService.getAllFlowIds();
166 for (Pair<FlowId, Dpid> pair : flowIds) {
167 EventEntry<Pair<FlowId, Dpid>> eventEntry =
168 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800169 flowIdEvents.add(eventEntry);
170 }
171
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800172 //
173 // Obtain the initial FlowEntryId state
174 //
175 Collection<Pair<FlowEntryId, Dpid>> flowEntryIds =
176 datagridService.getAllFlowEntryIds();
177 for (Pair<FlowEntryId, Dpid> pair : flowEntryIds) {
178 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
179 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
180 flowEntryIdEvents.add(eventEntry);
181 }
182
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800183 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800184 synchronized (allFlowPaths) {
185 processEvents();
186 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800187 }
188
189 /**
190 * Run the thread.
191 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800192 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800193 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800194 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800195 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700196
197 //
198 // The main loop
199 //
200 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
201 try {
202 while (true) {
203 EventEntry<?> eventEntry = networkEvents.take();
204 collection.add(eventEntry);
205 networkEvents.drainTo(collection);
206
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700207 //
208 // Demultiplex all events:
209 // - EventEntry<TopologyElement>
210 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700211 // - EventEntry<FlowEntry>
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800212 // - EventEntry<Pair<FlowId, Dpid>>
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800213 // - EventEntry<Pair<FlowEntryId, Dpid>>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700214 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700215 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800216 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700217 if (event.eventData() instanceof TopologyElement) {
218 EventEntry<TopologyElement> topologyEventEntry =
219 (EventEntry<TopologyElement>)event;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800220
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700221 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800222 continue;
223 }
224
225 // FlowPath event
226 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700227 EventEntry<FlowPath> flowPathEventEntry =
228 (EventEntry<FlowPath>)event;
229 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800230 continue;
231 }
232
233 // FlowEntry event
234 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700235 EventEntry<FlowEntry> flowEntryEventEntry =
236 (EventEntry<FlowEntry>)event;
237 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800238 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700239 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800240
241 // FlowId event
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800242 if (event.eventData() instanceof Pair) {
243 EventEntry<Pair<FlowId, Dpid>> flowIdEventEntry =
244 (EventEntry<Pair<FlowId, Dpid>>)event;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800245 flowIdEvents.add(flowIdEventEntry);
246 continue;
247 }
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800248
249 // Switch Dpid event
250 if (event.eventData() instanceof Dpid) {
251 EventEntry<Dpid> switchDpidEventEntry =
252 (EventEntry<Dpid>)event;
253 switchDpidEvents.add(switchDpidEventEntry);
254 continue;
255 }
256
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800257 // FlowEntryId event
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800258 // TODO: Fix the code below if we need again to handle
259 // the FlowEntryId events
260 /*
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800261 if (event.eventData() instanceof Pair) {
262 EventEntry<Pair<FlowEntryId, Dpid>> flowEntryIdEventEntry =
263 (EventEntry<Pair<FlowEntryId, Dpid>>)event;
264 flowEntryIdEvents.add(flowEntryIdEventEntry);
265 continue;
266 }
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800267 */
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700268 }
269 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700270
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700271 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800272 synchronized (allFlowPaths) {
273 processEvents();
274 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700275 }
276 } catch (Exception exception) {
277 log.debug("Exception processing Network Events: ", exception);
278 }
279 }
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800280
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700281 /**
282 * Process the events (if any)
283 */
284 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800285 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700286
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800287 if (enableOnrc2014MeasurementsFlows) {
288
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800289 PerformanceMonitor.start("EventHandler.ProcessAllEvents");
290
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800291 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty() &&
292 switchDpidEvents.isEmpty()) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800293 return; // Nothing to do
294 }
295
296 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
297
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800298 // Process the Switch Dpid events
Pavlin Radoslavov51800822014-01-12 22:33:40 -0800299 PerformanceMonitor.start("EventHandler.SwitchDpidEvents");
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800300 processSwitchDpidEvents();
Pavlin Radoslavov51800822014-01-12 22:33:40 -0800301 PerformanceMonitor.stop("EventHandler.SwitchDpidEvents");
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800302
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800303 // Process the Flow ID events
Pavlin Radoslavovcfcd2722014-01-12 22:32:36 -0800304 PerformanceMonitor.start("EventHandler.FlowIdEvents");
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800305 processFlowIdEvents(mySwitches);
Pavlin Radoslavovcfcd2722014-01-12 22:32:36 -0800306 PerformanceMonitor.stop("EventHandler.FlowIdEvents");
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800307
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800308 // Fetch the topology
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800309 PerformanceMonitor.start("EventHandler.ReadTopology");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800310 processTopologyEvents();
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800311 PerformanceMonitor.stop("EventHandler.ReadTopology");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800312
313 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800314 PerformanceMonitor.start("EventHandler.RecomputeFlows");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800315 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
316 if (recomputeFlowPath(flowPath))
317 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
318 }
319
320 // Assign the Flow Entry ID as needed
321 for (FlowPath flowPath : modifiedFlowPaths.values()) {
322 for (FlowEntry flowEntry : flowPath.flowEntries()) {
323 if (! flowEntry.isValidFlowEntryId()) {
324 long id = flowManager.getNextFlowEntryId();
325 flowEntry.setFlowEntryId(new FlowEntryId(id));
326 }
327 }
328 }
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800329 PerformanceMonitor.stop("EventHandler.RecomputeFlows");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800330
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800331 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800332 // Push the modified state to the database
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800333 //
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800334 PerformanceMonitor.start("EventHandler.WriteFlowsToDb");
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800335 for (FlowPath flowPath : modifiedFlowPaths.values()) {
336 //
337 // Delete the Flow Path from the Network Map
338 //
339 if (flowPath.flowPathUserState() ==
340 FlowPathUserState.FP_USER_DELETE) {
341 log.debug("Deleting Flow Path From Database: {}", flowPath);
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800342 // TODO: For now the deleting of a Flow Path is blocking
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800343 ParallelFlowDatabaseOperation.deleteFlow(dbHandler,
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800344 flowPath.flowId());
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800345 //
346 // NOTE: For now the sending of the notifications
347 // is outside of this loop, so the performance measurements
348 // are more accurate.
349 //
350 /*
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800351 // Send the notifications for the deleted Flow Entries
352 for (FlowEntry flowEntry : flowPath.flowEntries()) {
353 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
354 }
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800355 */
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800356
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800357 continue;
358 }
359
360 log.debug("Pushing Flow Path To Database: {}", flowPath);
361 //
362 // Write the Flow Path to the Network Map
363 //
364 ParallelFlowDatabaseOperation.addFlow(dbHandler, flowPath,
365 datagridService);
366 }
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800367 PerformanceMonitor.stop("EventHandler.WriteFlowsToDb");
368
369 //
370 // Send the notifications for the deleted Flow Entries
371 // NOTE: This code was pulled outside of the above loop,
372 // so the performance measurements are more accurate.
373 //
374 PerformanceMonitor.start("EventHandler.NotificationSend.FlowEntryRemoved");
375 for (FlowPath flowPath : modifiedFlowPaths.values()) {
376 if (flowPath.flowPathUserState() ==
377 FlowPathUserState.FP_USER_DELETE) {
378 for (FlowEntry flowEntry : flowPath.flowEntries()) {
379 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
380 }
381 }
382 }
Pavlin Radoslavovdbd09cc2014-01-12 18:13:35 -0800383 PerformanceMonitor.stop("EventHandler.NotificationSend.FlowEntryRemoved");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800384
385 // Cleanup
386 topologyEvents.clear();
387 flowIdEvents.clear();
Pavlin Radoslavov2d6e5f12014-01-10 16:34:05 -0800388 switchDpidEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800389 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800390 // NOTE: Keep a cache with my Flow Paths
391 // allFlowPaths.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800392 shouldRecomputeFlowPaths.clear();
393 modifiedFlowPaths.clear();
394
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800395 PerformanceMonitor.stop("EventHandler.ProcessAllEvents");
Pavlin Radoslavov8bd6d112014-01-12 20:12:37 -0800396
397
Brian O'Connor2daf7a92014-01-14 11:26:35 -0800398// PerformanceMonitor.report("EventHandler.SwitchDpidEvents");
399// PerformanceMonitor.report("EventHandler.FlowIdEvents");
400// PerformanceMonitor.report("EventHandler.ReadTopology");
401// PerformanceMonitor.report("EventHandler.RecomputeFlows");
402// PerformanceMonitor.report("EventHandler.WriteFlowsToDb");
403// PerformanceMonitor.report("EventHandler.NotificationSend.FlowEntryRemoved");
404// PerformanceMonitor.report("EventHandler.ProcessAllEvents");
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800405// PerformanceMonitor.report();
406// PerformanceMonitor.clear();
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800407
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800408 return;
409 }
410
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700411 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800412 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700413 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700414 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700415
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800416 processFlowPathEvents();
417 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800418 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800419 processFlowEntryEvents();
420
421 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800422 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800423 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800424 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800425 }
426
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800427 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800428 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800429
430 // Assign missing Flow Entry IDs
431 assignFlowEntryId(modifiedFlowEntries);
432
433 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800434 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800436 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
437 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800438
439 //
440 // Remove Flow Entries that were deleted
441 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800442 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800443 flowPath.dataPath().removeDeletedFlowEntries();
444
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800445 //
446 // Check if Flow Paths have been installed into all switches,
447 // and generate the appropriate events.
448 //
449 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
450
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800451 // Cleanup
452 topologyEvents.clear();
453 flowPathEvents.clear();
454 flowEntryEvents.clear();
455 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800456 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800457 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800458 checkIfInstalledFlowPaths.clear();
459 }
460
461 /**
462 * Check if Flow Paths have been installed into all switches,
463 * and generate the appropriate events.
464 *
465 * @param flowPaths the flowPaths to process.
466 */
467 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
468 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
469
470 Kryo kryo = kryoFactory.newKryo();
471
472 for (FlowPath flowPath : flowPaths) {
473 boolean isInstalled = true;
474
475 //
476 // Check whether all Flow Entries have been installed
477 //
478 for (FlowEntry flowEntry : flowPath.flowEntries()) {
479 if (flowEntry.flowEntrySwitchState() !=
480 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
481 isInstalled = false;
482 break;
483 }
484 }
485
486 if (isInstalled) {
487 // Create a copy and add it to the list
488 FlowPath copyFlowPath = kryo.copy(flowPath);
489 installedFlowPaths.add(copyFlowPath);
490 }
491 }
492 kryoFactory.deleteKryo(kryo);
493
494 // Generate an event for the installed Flow Path.
495 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800496 }
497
498 /**
499 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800500 *
501 * @param modifiedFlowPaths the Flow Paths to process.
502 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800503 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800504 private Collection<FlowEntry> extractModifiedFlowEntries(
505 Collection<FlowPath> modifiedFlowPaths) {
506 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800507
508 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800509 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800510 for (FlowEntry flowEntry : flowPath.flowEntries()) {
511 if (flowEntry.flowEntrySwitchState() ==
512 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800513 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800514 }
515 }
516 }
517 return modifiedFlowEntries;
518 }
519
520 /**
521 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800522 *
523 * @param modifiedFlowEnries the collection of Flow Entries that need
524 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800525 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800526 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800527 if (modifiedFlowEntries.isEmpty())
528 return;
529
530 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
531
532 //
533 // Assign the Flow Entry ID only for Flow Entries for my switches
534 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800535 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800536 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
537 if (mySwitch == null)
538 continue;
539 if (! flowEntry.isValidFlowEntryId()) {
540 long id = flowManager.getNextFlowEntryId();
541 flowEntry.setFlowEntryId(new FlowEntryId(id));
542 }
543 }
544 }
545
546 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800547 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800548 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800549 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800550 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800551 private void fixFlowFromDatabase(FlowPath flowPath) {
552 //
553 // TODO: Bug workaround / fix :
554 // method FlowDatabaseOperation.extractFlowEntry() doesn't
555 // fetch the inPort and outPort, hence we assign them here.
556 //
557 // Assign the inPort and outPort for the Flow Entries
558 for (FlowEntry flowEntry : flowPath.flowEntries()) {
559 // Set the inPort
560 do {
561 if (flowEntry.inPort() != null)
562 break;
563 if (flowEntry.flowEntryMatch() == null)
564 break;
565 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
566 flowEntry.setInPort(inPort);
567 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800568
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800569 // Set the outPort
570 do {
571 if (flowEntry.outPort() != null)
572 break;
573 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
574 if (fa.actionOutput() != null) {
575 Port outPort = new Port(fa.actionOutput().port().value());
576 flowEntry.setOutPort(outPort);
577 break;
578 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800579 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800580 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800581 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800582 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800583
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800584 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800585 * Process the Switch Dpid events.
586 */
587 private void processSwitchDpidEvents() {
588 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
589 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
590
591 //
592 // Process all Switch Dpid events and update the appropriate state
593 //
594 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
595 Dpid dpid = eventEntry.eventData();
596
597 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
598
599 // Compute the final set of added and removed switches
600 switch (eventEntry.eventType()) {
601 case ENTRY_ADD:
602 addedSwitches.put(dpid.value(), dpid);
603 removedSwitches.remove(dpid.value());
604 break;
605 case ENTRY_REMOVE:
606 addedSwitches.remove(dpid.value());
607 removedSwitches.put(dpid.value(), dpid);
608 break;
609 }
610 }
611
612 //
613 // Remove the Flows from the local cache if the removed
614 // switch is the Source Switch.
615 //
616 // TODO: This search can be expensive for a large number of flows
617 // and should be optmized.
618 //
619 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
620 for (Dpid switchDpid : removedSwitches.values()) {
621 for (FlowPath flowPath : allFlowPaths.values()) {
622 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
623 if (srcDpid.value() == switchDpid.value())
624 deleteFlowIds.add(flowPath.flowId());
625 }
626 }
627 //
628 // Remove the Flows from the local cache
629 //
630 for (FlowId flowId : deleteFlowIds)
631 allFlowPaths.remove(flowId.value());
632
633 // Get the Flows for the added switches
634 Collection<FlowPath> flowPaths =
635 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
636 addedSwitches.values());
637 for (FlowPath flowPath : flowPaths) {
638 allFlowPaths.put(flowPath.flowId().value(), flowPath);
639 }
640 }
641
642 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800643 * Process the Flow ID events.
644 *
645 * @param mySwitches the collection of my switches.
646 */
647 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800648 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
649
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800650 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800651 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800652 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800653 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
654 Pair<FlowId, Dpid> pair = eventEntry.eventData();
655 FlowId flowId = pair.first;
656 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800657
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800658 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
659 flowId, dpid);
660
661 //
662 // Ignore Flows if the Source Switch is not controlled by this
663 // instance.
664 //
665 if (mySwitches.get(dpid.value()) == null)
666 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800667
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800668 switch (eventEntry.eventType()) {
669 case ENTRY_ADD: {
670 //
671 // Add a new Flow Path
672 //
673 if (allFlowPaths.get(flowId.value()) != null) {
674 //
675 // TODO: What to do if the Flow Path already exists?
676 // Fow now, we just re-add it.
677 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800678 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800679 shouldFetchMyFlowIds.add(flowId);
680
681 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800682 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800683
684 case ENTRY_REMOVE: {
685 //
686 // Remove an existing Flow Path.
687 //
688 // Find the Flow Path, and mark the Flow and its Flow Entries
689 // for deletion.
690 //
691 FlowPath existingFlowPath =
692 allFlowPaths.get(flowId.value());
693 if (existingFlowPath == null)
694 continue; // Nothing to do
695
696 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
697 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
698 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
699 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
700 }
701
702 // Remove the Flow Path from the internal state
703 Long key = existingFlowPath.flowId().value();
704 allFlowPaths.remove(key);
705 shouldRecomputeFlowPaths.remove(key);
706 modifiedFlowPaths.put(key, existingFlowPath);
707
708 break;
709 }
710 }
711 }
712
713 // Get my Flows
714 Collection<FlowPath> myFlows =
Pavlin Radoslavov6602b6a2014-01-10 16:43:29 -0800715 ParallelFlowDatabaseOperation.getFlows(dbHandler,
716 shouldFetchMyFlowIds);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800717
718 for (FlowPath flowPath : myFlows) {
719 fixFlowFromDatabase(flowPath);
720
721 switch (flowPath.flowPathType()) {
722 case FP_TYPE_SHORTEST_PATH:
723 //
724 // Reset the Data Path, in case it was set already, because
725 // we are going to recompute it anyway.
726 //
727 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800728 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
729 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800730 break;
731 case FP_TYPE_EXPLICIT_PATH:
732 //
733 // Mark all Flow Entries for installation in the switches.
734 //
735 for (FlowEntry flowEntry : flowPath.flowEntries()) {
736 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
737 }
738 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
739 break;
740 case FP_TYPE_UNKNOWN:
741 log.error("FlowPath event with unknown type");
742 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800743 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800744 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800745 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800746 }
747
748 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800749 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800750 *
751 * @param mySwitches the collection of my switches.
752 * @return a collection of modified Flow Entries this instance needs
753 * to push to its own switches.
754 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800755 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800756 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
757
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800758 //
759 // Process all Flow ID events and update the appropriate state
760 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800761 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
762 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
763 FlowEntryId flowEntryId = pair.first;
764 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800765
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800766 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
767 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800768
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800769 if (mySwitches.get(dpid.value()) == null)
770 continue;
771
772 // Fetch the Flow Entry
773 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
774 flowEntryId);
775 if (flowEntry == null) {
776 log.debug("Flow Entry ID {} : Flow Entry not found!",
777 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800778 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800779 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800780 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800781 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800782
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800783 return modifiedFlowEntries;
784 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800785
786 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800787 * Process the Flow Path events.
788 */
789 private void processFlowPathEvents() {
790 //
791 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700792 //
793 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
794 FlowPath flowPath = eventEntry.eventData();
795
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800796 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800797
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700798 switch (eventEntry.eventType()) {
799 case ENTRY_ADD: {
800 //
801 // Add a new Flow Path
802 //
803 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
804 //
805 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800806 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700807 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700808 }
809
810 switch (flowPath.flowPathType()) {
811 case FP_TYPE_SHORTEST_PATH:
812 //
813 // Reset the Data Path, in case it was set already, because
814 // we are going to recompute it anyway.
815 //
816 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800817 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
818 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700819 break;
820 case FP_TYPE_EXPLICIT_PATH:
821 //
822 // Mark all Flow Entries for installation in the switches.
823 //
824 for (FlowEntry flowEntry : flowPath.flowEntries()) {
825 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
826 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800827 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700828 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800829 case FP_TYPE_UNKNOWN:
830 log.error("FlowPath event with unknown type");
831 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700832 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800833 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700834
835 break;
836 }
837
838 case ENTRY_REMOVE: {
839 //
840 // Remove an existing Flow Path.
841 //
842 // Find the Flow Path, and mark the Flow and its Flow Entries
843 // for deletion.
844 //
845 FlowPath existingFlowPath =
846 allFlowPaths.get(flowPath.flowId().value());
847 if (existingFlowPath == null)
848 continue; // Nothing to do
849
850 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
851 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
852 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
853 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
854 }
855
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800856 // Remove the Flow Path from the internal state
857 Long key = existingFlowPath.flowId().value();
858 allFlowPaths.remove(key);
859 shouldRecomputeFlowPaths.remove(key);
860 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700861
862 break;
863 }
864 }
865 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800866 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700867
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800868 /**
869 * Process the Topology events.
870 */
871 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800872 boolean isTopologyModified = false;
873
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800874 if (enableOnrc2014MeasurementsTopology) {
875 if (topologyEvents.isEmpty())
876 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800877
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800878 // TODO: Code for debugging purpose only
879 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
880 TopologyElement topologyElement = eventEntry.eventData();
881 log.debug("Topology Event: {} {}", eventEntry.eventType(),
882 topologyElement.toString());
883 }
884
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800885 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800886 topology.readFromDatabase(dbHandler);
887 log.debug("[AFTER] {}", topology.toString());
888 shouldRecomputeFlowPaths.putAll(allFlowPaths);
889 return;
890 }
891
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700892 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800893 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700894 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800895 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
896 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800897
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800898 log.debug("Topology Event: {} {}", eventEntry.eventType(),
899 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800900
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800901 switch (eventEntry.eventType()) {
902 case ENTRY_ADD:
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800903 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800904 break;
905 case ENTRY_REMOVE:
Naoki Shiota9f6fc212014-01-09 21:38:08 -0800906 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800907 break;
908 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700909 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700910 if (isTopologyModified) {
911 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800912 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700913 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800914 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700915
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800916 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800917 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800918 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800919 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800920 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800921 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800922
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700923 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800924 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700925 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800926 if (! unmatchedFlowEntryAdd.isEmpty()) {
927 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
928 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800929 // log.debug("Processing Unmatched Flow Entry: {}",
930 // flowEntry.toString());
931
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800932 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800933 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800934 remainingUpdates.put(flowEntry.flowEntryId().value(),
935 flowEntry);
936 continue;
937 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800938 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
939 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800940 remainingUpdates.put(flowEntry.flowEntryId().value(),
941 flowEntry);
942 continue;
943 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800944 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
945 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
946 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700947 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800948 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700949 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800950 }
951
952 /**
953 * Process the Flow Entry events.
954 */
955 private void processFlowEntryEvents() {
956 FlowPath flowPath;
957 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700958
959 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800960 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700961 //
962 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
963 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800964
965 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800966 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800967
968 if ((! flowEntry.isValidFlowId()) ||
969 (! flowEntry.isValidFlowEntryId())) {
970 continue;
971 }
972
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700973 switch (eventEntry.eventType()) {
974 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800975 flowPath = allFlowPaths.get(flowEntry.flowId().value());
976 if (flowPath == null) {
977 // Flow Path not found: keep the entry for later matching
978 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
979 flowEntry);
980 break;
981 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800982 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
983 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800984 // Flow Entry not found: keep the entry for later matching
985 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
986 flowEntry);
987 break;
988 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800989 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
990 // Add the updated Flow Path to the list of updated paths
991 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
992 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700993 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800994
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700995 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800996 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
997 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800998 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800999 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -08001000
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001001 flowPath = allFlowPaths.get(flowEntry.flowId().value());
1002 if (flowPath == null) {
1003 // Flow Path not found: ignore the update
1004 break;
1005 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001006 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
1007 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -08001008 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001009 break;
1010 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001011 if (updateFlowEntryRemove(flowPath, localFlowEntry,
1012 flowEntry)) {
1013 // Add the updated Flow Path to the list of updated paths
1014 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
1015 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001016 break;
1017 }
1018 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001019 }
1020
1021 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001022 * Find a Flow Entry that should be updated because of an external
1023 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001024 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001025 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001026 * @param newFlowEntry the FlowEntry with the new state.
1027 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001028 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001029 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
1030 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001031 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001032 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001033 //
1034 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001035 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001036 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001037 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001038 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001039
1040 //
1041 // Local Flow Entry match found
1042 //
1043 if (localFlowEntry.isValidFlowEntryId()) {
1044 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001045 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001046 //
1047 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001048 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001049 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001050 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001051 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001052 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001053 return localFlowEntry;
1054 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001055
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001056 return null; // Entry not found
1057 }
1058
1059 /**
1060 * Update a Flow Entry because of an external ENTRY_ADD event.
1061 *
1062 * @param flowPath the FlowPath for the Flow Entry to update.
1063 * @param localFlowEntry the local Flow Entry to update.
1064 * @param newFlowEntry the FlowEntry with the new state.
1065 * @return true if the local Flow Entry was updated, otherwise false.
1066 */
1067 private boolean updateFlowEntryAdd(FlowPath flowPath,
1068 FlowEntry localFlowEntry,
1069 FlowEntry newFlowEntry) {
1070 boolean updated = false;
1071
1072 if (localFlowEntry.flowEntryUserState() ==
1073 FlowEntryUserState.FE_USER_DELETE) {
1074 // Don't add-back a Flow Entry that is already deleted
1075 return false;
1076 }
1077
1078 if (! localFlowEntry.isValidFlowEntryId()) {
1079 // Update the Flow Entry ID
1080 FlowEntryId flowEntryId =
1081 new FlowEntryId(newFlowEntry.flowEntryId().value());
1082 localFlowEntry.setFlowEntryId(flowEntryId);
1083 updated = true;
1084 }
1085
1086 //
1087 // Update the local Flow Entry, and keep state to check
1088 // if the Flow Path has been installed.
1089 //
1090 if (localFlowEntry.flowEntryUserState() !=
1091 newFlowEntry.flowEntryUserState()) {
1092 localFlowEntry.setFlowEntryUserState(
1093 newFlowEntry.flowEntryUserState());
1094 updated = true;
1095 }
1096 if (localFlowEntry.flowEntrySwitchState() !=
1097 newFlowEntry.flowEntrySwitchState()) {
1098 localFlowEntry.setFlowEntrySwitchState(
1099 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001100 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001101 updated = true;
1102 }
1103
1104 return updated;
1105 }
1106
1107 /**
1108 * Find a Flow Entry that should be updated because of an external
1109 * ENTRY_REMOVE event.
1110 *
1111 * @param flowPath the FlowPath for the Flow Entry to update.
1112 * @param newFlowEntry the FlowEntry with the new state.
1113 * @return the Flow Entry that should be updated if found, otherwise null.
1114 */
1115 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1116 FlowEntry newFlowEntry) {
1117 //
1118 // Iterate over all Flow Entries and find a match based on
1119 // the Flow Entry ID.
1120 //
1121 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1122 if (! localFlowEntry.isValidFlowEntryId())
1123 continue;
1124 if (localFlowEntry.flowEntryId().value() !=
1125 newFlowEntry.flowEntryId().value()) {
1126 continue;
1127 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001128 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001129 }
1130
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001131 return null; // Entry not found
1132 }
1133
1134 /**
1135 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1136 *
1137 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001138 * @param localFlowEntry the local Flow Entry to update.
1139 * @param newFlowEntry the FlowEntry with the new state.
1140 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001141 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001142 private boolean updateFlowEntryRemove(FlowPath flowPath,
1143 FlowEntry localFlowEntry,
1144 FlowEntry newFlowEntry) {
1145 boolean updated = false;
1146
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001147 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001148 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001149 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001150 if (localFlowEntry.flowEntryUserState() !=
1151 newFlowEntry.flowEntryUserState()) {
1152 localFlowEntry.setFlowEntryUserState(
1153 newFlowEntry.flowEntryUserState());
1154 updated = true;
1155 }
1156 if (localFlowEntry.flowEntrySwitchState() !=
1157 newFlowEntry.flowEntrySwitchState()) {
1158 localFlowEntry.setFlowEntrySwitchState(
1159 newFlowEntry.flowEntrySwitchState());
1160 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001161 }
1162
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001163 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001164 }
1165
1166 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001167 * Recompute a Flow Path.
1168 *
1169 * @param flowPath the Flow Path to recompute.
1170 * @return true if the recomputed Flow Path has changed, otherwise false.
1171 */
1172 private boolean recomputeFlowPath(FlowPath flowPath) {
1173 boolean hasChanged = false;
1174
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001175 if (enableOnrc2014MeasurementsFlows) {
1176 // Cleanup the deleted Flow Entries from the earlier iteration
1177 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001178
1179 //
1180 // TODO: Fake it that the Flow Entries have been already pushed
1181 // into the switches, so we don't push them again.
1182 //
1183 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1184 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1185 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001186 }
1187
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001188 //
1189 // Test whether the Flow Path needs to be recomputed
1190 //
1191 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001192 case FP_TYPE_UNKNOWN:
1193 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001194 case FP_TYPE_SHORTEST_PATH:
1195 break;
1196 case FP_TYPE_EXPLICIT_PATH:
1197 return false; // An explicit path never changes
1198 }
1199
1200 DataPath oldDataPath = flowPath.dataPath();
1201
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001202 // Compute the new path
Naoki Shiota9f6fc212014-01-09 21:38:08 -08001203 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001204 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001205
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001206 if (newDataPath == null) {
1207 // We need the DataPath to compare the paths
1208 newDataPath = new DataPath();
1209 }
1210 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1211
1212 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001213 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001214 //
1215 if (oldDataPath.flowEntries().size() !=
1216 newDataPath.flowEntries().size()) {
1217 hasChanged = true;
1218 } else {
1219 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1220 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1221 while (oldIter.hasNext() && newIter.hasNext()) {
1222 FlowEntry oldFlowEntry = oldIter.next();
1223 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001224 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1225 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001226 hasChanged = true;
1227 break;
1228 }
1229 }
1230 }
1231 if (! hasChanged)
1232 return hasChanged;
1233
1234 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001235 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001236 // - If a Flow Entry for a switch is in the old data path, but not
1237 // in the new data path, then mark it for deletion.
1238 // - If a Flow Entry for a switch is in the new data path, but not
1239 // in the old data path, then mark it for addition.
1240 // - If a Flow Entry for a switch is in both the old and the new
1241 // data path, but it has changed, e.g., the incoming and/or outgoing
1242 // port(s), then mark the old Flow Entry for deletion, and mark
1243 // the new Flow Entry for addition.
1244 // - If a Flow Entry for a switch is in both the old and the new
1245 // data path, and it hasn't changed, then just keep it.
1246 //
1247 // NOTE: We use the Switch DPID of each entry to match the entries
1248 //
1249 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1250 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1251 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1252 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1253
1254 // Prepare maps with the Flow Entries, so they are fast to lookup
1255 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1256 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1257 for (FlowEntry flowEntry : newDataPath.flowEntries())
1258 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1259
1260 //
1261 // Find the old Flow Entries that should be deleted
1262 //
1263 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1264 FlowEntry newFlowEntry =
1265 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1266 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001267 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001268 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1269 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1270 deletedFlowEntries.add(oldFlowEntry);
1271 }
1272 }
1273
1274 //
1275 // Find the new Flow Entries that should be added or updated
1276 //
1277 int idx = 0;
1278 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1279 FlowEntry oldFlowEntry =
1280 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1281
1282 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001283 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1284 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001285 //
1286 // Both Flow Entries are same
1287 //
1288 finalFlowEntries.add(oldFlowEntry);
1289 idx++;
1290 continue;
1291 }
1292
1293 if (oldFlowEntry != null) {
1294 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001295 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001296 //
1297 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1298 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1299 deletedFlowEntries.add(oldFlowEntry);
1300 }
1301
1302 //
1303 // Add the new Flow Entry
1304 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001305 //
1306 // NOTE: Assign only the Flow ID.
1307 // The Flow Entry ID is assigned later only for the Flow Entries
1308 // this instance is responsible for.
1309 //
1310 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001311
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001312 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001313 // Copy the Flow timeouts
1314 //
1315 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1316 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1317
1318 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001319 // Allocate the FlowEntryMatch by copying the default one
1320 // from the FlowPath (if set).
1321 //
1322 FlowEntryMatch flowEntryMatch = null;
1323 if (flowPath.flowEntryMatch() != null)
1324 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1325 else
1326 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001327 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001328
1329 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001330 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1331
1332 //
1333 // Set the actions:
1334 // If the first Flow Entry, copy the Flow Path actions to it.
1335 //
1336 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1337 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1338 FlowEntryActions flowActions =
1339 new FlowEntryActions(flowPath.flowEntryActions());
1340 for (FlowEntryAction action : flowActions.actions())
1341 flowEntryActions.addAction(action);
1342 }
1343 idx++;
1344
1345 //
1346 // Add the outgoing port output action
1347 //
1348 FlowEntryAction flowEntryAction = new FlowEntryAction();
1349 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1350 flowEntryActions.addAction(flowEntryAction);
1351
1352 //
1353 // Set the state of the new Flow Entry
1354 //
1355 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1356 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1357 finalFlowEntries.add(newFlowEntry);
1358 }
1359
1360 //
1361 // Replace the old Flow Entries with the new Flow Entries.
1362 // Note that the Flow Entries that will be deleted are added at
1363 // the end.
1364 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001365 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001366 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1367
1368 return hasChanged;
1369 }
1370
1371 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001372 * Receive a notification that a Flow is added.
1373 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001374 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001375 */
1376 @Override
1377 public void notificationRecvFlowAdded(FlowPath flowPath) {
1378 EventEntry<FlowPath> eventEntry =
1379 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1380 networkEvents.add(eventEntry);
1381 }
1382
1383 /**
1384 * Receive a notification that a Flow is removed.
1385 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001386 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001387 */
1388 @Override
1389 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1390 EventEntry<FlowPath> eventEntry =
1391 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1392 networkEvents.add(eventEntry);
1393 }
1394
1395 /**
1396 * Receive a notification that a Flow is updated.
1397 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001398 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001399 */
1400 @Override
1401 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1402 // NOTE: The ADD and UPDATE events are processed in same way
1403 EventEntry<FlowPath> eventEntry =
1404 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1405 networkEvents.add(eventEntry);
1406 }
1407
1408 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001409 * Receive a notification that a FlowEntry is added.
1410 *
1411 * @param flowEntry the FlowEntry that is added.
1412 */
1413 @Override
1414 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001415 if (enableOnrc2014MeasurementsFlows) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -08001416// String tag = "EventHandler.AddFlowEntryToSwitch." + flowEntry.flowEntryId();
1417 String tag = "EventHandler.AddFlowEntryToSwitch";
1418 PerformanceMonitor.Measurement m = PerformanceMonitor.start(tag);
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001419 Collection entries = new ArrayList();
1420 entries.add(flowEntry);
1421 flowManager.pushModifiedFlowEntriesToSwitches(entries);
Brian O'Connor2daf7a92014-01-14 11:26:35 -08001422// PerformanceMonitor.stop(tag);
1423 m.stop();
1424// PerformanceMonitor.report(tag);
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001425 return;
1426 }
1427
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001428 EventEntry<FlowEntry> eventEntry =
1429 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1430 networkEvents.add(eventEntry);
1431 }
1432
1433 /**
1434 * Receive a notification that a FlowEntry is removed.
1435 *
1436 * @param flowEntry the FlowEntry that is removed.
1437 */
1438 @Override
1439 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001440 if (enableOnrc2014MeasurementsFlows) {
Brian O'Connor2daf7a92014-01-14 11:26:35 -08001441// String tag = "EventHandler.RemoveFlowEntryFromSwitch." + flowEntry.flowEntryId();
1442 String tag = "EventHandler.RemoveFlowEntryFromSwitch";
1443 PerformanceMonitor.Measurement m = PerformanceMonitor.start(tag);
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001444 //
1445 // NOTE: Must update the state to DELETE, because
1446 // the notification contains the original state.
1447 //
1448 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1449
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001450 Collection entries = new ArrayList();
1451 entries.add(flowEntry);
1452 flowManager.pushModifiedFlowEntriesToSwitches(entries);
Brian O'Connor2daf7a92014-01-14 11:26:35 -08001453// PerformanceMonitor.stop(tag);
1454 m.stop();
1455// PerformanceMonitor.report(tag);
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001456 return;
1457 }
1458
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001459 EventEntry<FlowEntry> eventEntry =
1460 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1461 networkEvents.add(eventEntry);
1462 }
1463
1464 /**
1465 * Receive a notification that a FlowEntry is updated.
1466 *
1467 * @param flowEntry the FlowEntry that is updated.
1468 */
1469 @Override
1470 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001471 if (enableOnrc2014MeasurementsFlows) {
1472 Collection entries = new ArrayList();
1473 entries.add(flowEntry);
1474 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1475 return;
1476 }
1477
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001478 // NOTE: The ADD and UPDATE events are processed in same way
1479 EventEntry<FlowEntry> eventEntry =
1480 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1481 networkEvents.add(eventEntry);
1482 }
1483
1484 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001485 * Receive a notification that a FlowId is added.
1486 *
1487 * @param flowId the FlowId that is added.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001488 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001489 */
1490 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001491 public void notificationRecvFlowIdAdded(FlowId flowId, Dpid dpid) {
1492 Pair flowIdPair = new Pair(flowId, dpid);
1493
1494 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1495 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001496 networkEvents.add(eventEntry);
1497 }
1498
1499 /**
1500 * Receive a notification that a FlowId is removed.
1501 *
1502 * @param flowId the FlowId that is removed.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001503 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001504 */
1505 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001506 public void notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1507 Pair flowIdPair = new Pair(flowId, dpid);
1508
1509 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1510 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001511 networkEvents.add(eventEntry);
1512 }
1513
1514 /**
1515 * Receive a notification that a FlowId is updated.
1516 *
1517 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001518 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001519 */
1520 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001521 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1522 Pair flowIdPair = new Pair(flowId, dpid);
1523
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001524 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001525 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1526 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001527 networkEvents.add(eventEntry);
1528 }
1529
1530 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001531 * Receive a notification that a FlowEntryId is added.
1532 *
1533 * @param flowEntryId the FlowEntryId that is added.
1534 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1535 */
1536 @Override
1537 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1538 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001539 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1540
1541 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1542 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001543 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001544 }
1545
1546 /**
1547 * Receive a notification that a FlowEntryId is removed.
1548 *
1549 * @param flowEntryId the FlowEntryId that is removed.
1550 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1551 */
1552 @Override
1553 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1554 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001555 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1556
1557 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1558 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001559 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001560 }
1561
1562 /**
1563 * Receive a notification that a FlowEntryId is updated.
1564 *
1565 * @param flowEntryId the FlowEntryId that is updated.
1566 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1567 */
1568 @Override
1569 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1570 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001571 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1572
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001573 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001574 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1575 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001576 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001577 }
1578
1579 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001580 * Receive a notification that a Topology Element is added.
1581 *
1582 * @param topologyElement the Topology Element that is added.
1583 */
1584 @Override
1585 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1586 EventEntry<TopologyElement> eventEntry =
1587 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1588 networkEvents.add(eventEntry);
1589 }
1590
1591 /**
1592 * Receive a notification that a Topology Element is removed.
1593 *
1594 * @param topologyElement the Topology Element that is removed.
1595 */
1596 @Override
1597 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1598 EventEntry<TopologyElement> eventEntry =
1599 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1600 networkEvents.add(eventEntry);
1601 }
1602
1603 /**
1604 * Receive a notification that a Topology Element is updated.
1605 *
1606 * @param topologyElement the Topology Element that is updated.
1607 */
1608 @Override
1609 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1610 // NOTE: The ADD and UPDATE events are processed in same way
1611 EventEntry<TopologyElement> eventEntry =
1612 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1613 networkEvents.add(eventEntry);
1614 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001615
1616 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001617 * Receive a notification that a switch is added to this instance.
1618 *
1619 * @param sw the switch that is added.
1620 */
1621 @Override
1622 public void addedSwitch(IOFSwitch sw) {
1623 Dpid dpid = new Dpid(sw.getId());
1624 EventEntry<Dpid> eventEntry =
1625 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1626 networkEvents.add(eventEntry);
1627 }
1628
1629 /**
1630 * Receive a notification that a switch is removed from this instance.
1631 *
1632 * @param sw the switch that is removed.
1633 */
1634 @Override
1635 public void removedSwitch(IOFSwitch sw) {
1636 Dpid dpid = new Dpid(sw.getId());
1637 EventEntry<Dpid> eventEntry =
1638 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1639 networkEvents.add(eventEntry);
1640 }
1641
1642 /**
1643 * Receive a notification that the ports on a switch have changed.
1644 */
1645 @Override
1646 public void switchPortChanged(Long switchId) {
1647 // Nothing to do
1648 }
1649
1650 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001651 * Get a sorted copy of all Flow Paths.
1652 *
1653 * @return a sorted copy of all Flow Paths.
1654 */
1655 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1656 SortedMap<Long, FlowPath> sortedFlowPaths =
1657 new TreeMap<Long, FlowPath>();
1658
1659 //
1660 // TODO: For now we use serialization/deserialization to create
1661 // a copy of each Flow Path. In the future, we should use proper
1662 // copy constructors.
1663 //
1664 Kryo kryo = kryoFactory.newKryo();
1665 synchronized (allFlowPaths) {
1666 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1667 FlowPath origFlowPath = entry.getValue();
1668 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1669 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1670 }
1671 }
1672 kryoFactory.deleteKryo(kryo);
1673
1674 return sortedFlowPaths;
1675 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001676}