blob: b44a3de3d213f028c18cf9add91e601d8f9cc38e [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
299 processSwitchDpidEvents();
300
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800301 // Process the Flow ID events
302 processFlowIdEvents(mySwitches);
303
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800304 // Fetch the topology
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800305 PerformanceMonitor.start("EventHandler.ReadTopology");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800306 processTopologyEvents();
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800307 PerformanceMonitor.stop("EventHandler.ReadTopology");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800308
309 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800310 PerformanceMonitor.start("EventHandler.RecomputeFlows");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800311 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
312 if (recomputeFlowPath(flowPath))
313 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
314 }
315
316 // Assign the Flow Entry ID as needed
317 for (FlowPath flowPath : modifiedFlowPaths.values()) {
318 for (FlowEntry flowEntry : flowPath.flowEntries()) {
319 if (! flowEntry.isValidFlowEntryId()) {
320 long id = flowManager.getNextFlowEntryId();
321 flowEntry.setFlowEntryId(new FlowEntryId(id));
322 }
323 }
324 }
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800325 PerformanceMonitor.stop("EventHandler.RecomputeFlows");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800326
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800327 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800328 // Push the modified state to the database
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800329 //
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800330 PerformanceMonitor.start("EventHandler.WriteFlowsToDb");
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800331 for (FlowPath flowPath : modifiedFlowPaths.values()) {
332 //
333 // Delete the Flow Path from the Network Map
334 //
335 if (flowPath.flowPathUserState() ==
336 FlowPathUserState.FP_USER_DELETE) {
337 log.debug("Deleting Flow Path From Database: {}", flowPath);
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800338 // TODO: For now the deleting of a Flow Path is blocking
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800339 ParallelFlowDatabaseOperation.deleteFlow(dbHandler,
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800340 flowPath.flowId());
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800341 //
342 // NOTE: For now the sending of the notifications
343 // is outside of this loop, so the performance measurements
344 // are more accurate.
345 //
346 /*
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800347 // Send the notifications for the deleted Flow Entries
348 for (FlowEntry flowEntry : flowPath.flowEntries()) {
349 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
350 }
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800351 */
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800352
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800353 continue;
354 }
355
356 log.debug("Pushing Flow Path To Database: {}", flowPath);
357 //
358 // Write the Flow Path to the Network Map
359 //
360 ParallelFlowDatabaseOperation.addFlow(dbHandler, flowPath,
361 datagridService);
362 }
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800363 PerformanceMonitor.stop("EventHandler.WriteFlowsToDb");
364
365 //
366 // Send the notifications for the deleted Flow Entries
367 // NOTE: This code was pulled outside of the above loop,
368 // so the performance measurements are more accurate.
369 //
370 PerformanceMonitor.start("EventHandler.NotificationSend.FlowEntryRemoved");
371 for (FlowPath flowPath : modifiedFlowPaths.values()) {
372 if (flowPath.flowPathUserState() ==
373 FlowPathUserState.FP_USER_DELETE) {
374 for (FlowEntry flowEntry : flowPath.flowEntries()) {
375 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
376 }
377 }
378 }
Pavlin Radoslavovdbd09cc2014-01-12 18:13:35 -0800379 PerformanceMonitor.stop("EventHandler.NotificationSend.FlowEntryRemoved");
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800380
381 // Cleanup
382 topologyEvents.clear();
383 flowIdEvents.clear();
Pavlin Radoslavov2d6e5f12014-01-10 16:34:05 -0800384 switchDpidEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800385 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800386 // NOTE: Keep a cache with my Flow Paths
387 // allFlowPaths.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800388 shouldRecomputeFlowPaths.clear();
389 modifiedFlowPaths.clear();
390
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800391 PerformanceMonitor.stop("EventHandler.ProcessAllEvents");
Pavlin Radoslavov8bd6d112014-01-12 20:12:37 -0800392
393
394 PerformanceMonitor.report("EventHandler.ReadTopology");
395 PerformanceMonitor.report("EventHandler.RecomputeFlows");
396 PerformanceMonitor.report("EventHandler.WriteFlowsToDb");
397 PerformanceMonitor.report("EventHandler.NotificationSend.FlowEntryRemoved");
398 PerformanceMonitor.report("EventHandler.ProcessAllEvents");
Pavlin Radoslavove2497672014-01-12 18:03:35 -0800399
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800400 return;
401 }
402
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700403 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800404 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700405 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700406 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700407
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800408 processFlowPathEvents();
409 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800410 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800411 processFlowEntryEvents();
412
413 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800414 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800415 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800416 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800417 }
418
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800419 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800420 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800421
422 // Assign missing Flow Entry IDs
423 assignFlowEntryId(modifiedFlowEntries);
424
425 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800426 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800427 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800428 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
429 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800430
431 //
432 // Remove Flow Entries that were deleted
433 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800434 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435 flowPath.dataPath().removeDeletedFlowEntries();
436
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800437 //
438 // Check if Flow Paths have been installed into all switches,
439 // and generate the appropriate events.
440 //
441 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
442
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800443 // Cleanup
444 topologyEvents.clear();
445 flowPathEvents.clear();
446 flowEntryEvents.clear();
447 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800448 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800449 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800450 checkIfInstalledFlowPaths.clear();
451 }
452
453 /**
454 * Check if Flow Paths have been installed into all switches,
455 * and generate the appropriate events.
456 *
457 * @param flowPaths the flowPaths to process.
458 */
459 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
460 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
461
462 Kryo kryo = kryoFactory.newKryo();
463
464 for (FlowPath flowPath : flowPaths) {
465 boolean isInstalled = true;
466
467 //
468 // Check whether all Flow Entries have been installed
469 //
470 for (FlowEntry flowEntry : flowPath.flowEntries()) {
471 if (flowEntry.flowEntrySwitchState() !=
472 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
473 isInstalled = false;
474 break;
475 }
476 }
477
478 if (isInstalled) {
479 // Create a copy and add it to the list
480 FlowPath copyFlowPath = kryo.copy(flowPath);
481 installedFlowPaths.add(copyFlowPath);
482 }
483 }
484 kryoFactory.deleteKryo(kryo);
485
486 // Generate an event for the installed Flow Path.
487 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800488 }
489
490 /**
491 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800492 *
493 * @param modifiedFlowPaths the Flow Paths to process.
494 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800495 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800496 private Collection<FlowEntry> extractModifiedFlowEntries(
497 Collection<FlowPath> modifiedFlowPaths) {
498 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800499
500 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800501 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800502 for (FlowEntry flowEntry : flowPath.flowEntries()) {
503 if (flowEntry.flowEntrySwitchState() ==
504 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800505 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800506 }
507 }
508 }
509 return modifiedFlowEntries;
510 }
511
512 /**
513 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800514 *
515 * @param modifiedFlowEnries the collection of Flow Entries that need
516 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800517 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800518 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800519 if (modifiedFlowEntries.isEmpty())
520 return;
521
522 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
523
524 //
525 // Assign the Flow Entry ID only for Flow Entries for my switches
526 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800527 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800528 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
529 if (mySwitch == null)
530 continue;
531 if (! flowEntry.isValidFlowEntryId()) {
532 long id = flowManager.getNextFlowEntryId();
533 flowEntry.setFlowEntryId(new FlowEntryId(id));
534 }
535 }
536 }
537
538 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800539 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800540 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800541 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800542 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800543 private void fixFlowFromDatabase(FlowPath flowPath) {
544 //
545 // TODO: Bug workaround / fix :
546 // method FlowDatabaseOperation.extractFlowEntry() doesn't
547 // fetch the inPort and outPort, hence we assign them here.
548 //
549 // Assign the inPort and outPort for the Flow Entries
550 for (FlowEntry flowEntry : flowPath.flowEntries()) {
551 // Set the inPort
552 do {
553 if (flowEntry.inPort() != null)
554 break;
555 if (flowEntry.flowEntryMatch() == null)
556 break;
557 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
558 flowEntry.setInPort(inPort);
559 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800560
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800561 // Set the outPort
562 do {
563 if (flowEntry.outPort() != null)
564 break;
565 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
566 if (fa.actionOutput() != null) {
567 Port outPort = new Port(fa.actionOutput().port().value());
568 flowEntry.setOutPort(outPort);
569 break;
570 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800571 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800572 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800573 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800574 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800575
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800576 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800577 * Process the Switch Dpid events.
578 */
579 private void processSwitchDpidEvents() {
580 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
581 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
582
583 //
584 // Process all Switch Dpid events and update the appropriate state
585 //
586 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
587 Dpid dpid = eventEntry.eventData();
588
589 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
590
591 // Compute the final set of added and removed switches
592 switch (eventEntry.eventType()) {
593 case ENTRY_ADD:
594 addedSwitches.put(dpid.value(), dpid);
595 removedSwitches.remove(dpid.value());
596 break;
597 case ENTRY_REMOVE:
598 addedSwitches.remove(dpid.value());
599 removedSwitches.put(dpid.value(), dpid);
600 break;
601 }
602 }
603
604 //
605 // Remove the Flows from the local cache if the removed
606 // switch is the Source Switch.
607 //
608 // TODO: This search can be expensive for a large number of flows
609 // and should be optmized.
610 //
611 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
612 for (Dpid switchDpid : removedSwitches.values()) {
613 for (FlowPath flowPath : allFlowPaths.values()) {
614 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
615 if (srcDpid.value() == switchDpid.value())
616 deleteFlowIds.add(flowPath.flowId());
617 }
618 }
619 //
620 // Remove the Flows from the local cache
621 //
622 for (FlowId flowId : deleteFlowIds)
623 allFlowPaths.remove(flowId.value());
624
625 // Get the Flows for the added switches
626 Collection<FlowPath> flowPaths =
627 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
628 addedSwitches.values());
629 for (FlowPath flowPath : flowPaths) {
630 allFlowPaths.put(flowPath.flowId().value(), flowPath);
631 }
632 }
633
634 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800635 * Process the Flow ID events.
636 *
637 * @param mySwitches the collection of my switches.
638 */
639 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800640 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
641
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800642 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800643 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800644 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800645 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
646 Pair<FlowId, Dpid> pair = eventEntry.eventData();
647 FlowId flowId = pair.first;
648 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800649
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800650 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
651 flowId, dpid);
652
653 //
654 // Ignore Flows if the Source Switch is not controlled by this
655 // instance.
656 //
657 if (mySwitches.get(dpid.value()) == null)
658 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800659
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800660 switch (eventEntry.eventType()) {
661 case ENTRY_ADD: {
662 //
663 // Add a new Flow Path
664 //
665 if (allFlowPaths.get(flowId.value()) != null) {
666 //
667 // TODO: What to do if the Flow Path already exists?
668 // Fow now, we just re-add it.
669 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800670 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800671 shouldFetchMyFlowIds.add(flowId);
672
673 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800674 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800675
676 case ENTRY_REMOVE: {
677 //
678 // Remove an existing Flow Path.
679 //
680 // Find the Flow Path, and mark the Flow and its Flow Entries
681 // for deletion.
682 //
683 FlowPath existingFlowPath =
684 allFlowPaths.get(flowId.value());
685 if (existingFlowPath == null)
686 continue; // Nothing to do
687
688 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
689 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
690 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
691 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
692 }
693
694 // Remove the Flow Path from the internal state
695 Long key = existingFlowPath.flowId().value();
696 allFlowPaths.remove(key);
697 shouldRecomputeFlowPaths.remove(key);
698 modifiedFlowPaths.put(key, existingFlowPath);
699
700 break;
701 }
702 }
703 }
704
705 // Get my Flows
706 Collection<FlowPath> myFlows =
Pavlin Radoslavov6602b6a2014-01-10 16:43:29 -0800707 ParallelFlowDatabaseOperation.getFlows(dbHandler,
708 shouldFetchMyFlowIds);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800709
710 for (FlowPath flowPath : myFlows) {
711 fixFlowFromDatabase(flowPath);
712
713 switch (flowPath.flowPathType()) {
714 case FP_TYPE_SHORTEST_PATH:
715 //
716 // Reset the Data Path, in case it was set already, because
717 // we are going to recompute it anyway.
718 //
719 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800720 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
721 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800722 break;
723 case FP_TYPE_EXPLICIT_PATH:
724 //
725 // Mark all Flow Entries for installation in the switches.
726 //
727 for (FlowEntry flowEntry : flowPath.flowEntries()) {
728 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
729 }
730 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
731 break;
732 case FP_TYPE_UNKNOWN:
733 log.error("FlowPath event with unknown type");
734 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800735 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800736 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800737 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800738 }
739
740 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800741 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800742 *
743 * @param mySwitches the collection of my switches.
744 * @return a collection of modified Flow Entries this instance needs
745 * to push to its own switches.
746 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800747 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800748 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
749
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800750 //
751 // Process all Flow ID events and update the appropriate state
752 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800753 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
754 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
755 FlowEntryId flowEntryId = pair.first;
756 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800757
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800758 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
759 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800760
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800761 if (mySwitches.get(dpid.value()) == null)
762 continue;
763
764 // Fetch the Flow Entry
765 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
766 flowEntryId);
767 if (flowEntry == null) {
768 log.debug("Flow Entry ID {} : Flow Entry not found!",
769 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800770 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800771 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800772 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800773 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800774
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800775 return modifiedFlowEntries;
776 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800777
778 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800779 * Process the Flow Path events.
780 */
781 private void processFlowPathEvents() {
782 //
783 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700784 //
785 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
786 FlowPath flowPath = eventEntry.eventData();
787
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800788 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800789
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700790 switch (eventEntry.eventType()) {
791 case ENTRY_ADD: {
792 //
793 // Add a new Flow Path
794 //
795 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
796 //
797 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800798 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700799 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700800 }
801
802 switch (flowPath.flowPathType()) {
803 case FP_TYPE_SHORTEST_PATH:
804 //
805 // Reset the Data Path, in case it was set already, because
806 // we are going to recompute it anyway.
807 //
808 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800809 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
810 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700811 break;
812 case FP_TYPE_EXPLICIT_PATH:
813 //
814 // Mark all Flow Entries for installation in the switches.
815 //
816 for (FlowEntry flowEntry : flowPath.flowEntries()) {
817 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
818 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800819 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700820 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800821 case FP_TYPE_UNKNOWN:
822 log.error("FlowPath event with unknown type");
823 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700824 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800825 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700826
827 break;
828 }
829
830 case ENTRY_REMOVE: {
831 //
832 // Remove an existing Flow Path.
833 //
834 // Find the Flow Path, and mark the Flow and its Flow Entries
835 // for deletion.
836 //
837 FlowPath existingFlowPath =
838 allFlowPaths.get(flowPath.flowId().value());
839 if (existingFlowPath == null)
840 continue; // Nothing to do
841
842 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
843 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
844 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
845 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
846 }
847
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800848 // Remove the Flow Path from the internal state
849 Long key = existingFlowPath.flowId().value();
850 allFlowPaths.remove(key);
851 shouldRecomputeFlowPaths.remove(key);
852 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700853
854 break;
855 }
856 }
857 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800858 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700859
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800860 /**
861 * Process the Topology events.
862 */
863 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800864 boolean isTopologyModified = false;
865
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800866 if (enableOnrc2014MeasurementsTopology) {
867 if (topologyEvents.isEmpty())
868 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800869
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800870 // TODO: Code for debugging purpose only
871 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
872 TopologyElement topologyElement = eventEntry.eventData();
873 log.debug("Topology Event: {} {}", eventEntry.eventType(),
874 topologyElement.toString());
875 }
876
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800877 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800878 topology.readFromDatabase(dbHandler);
879 log.debug("[AFTER] {}", topology.toString());
880 shouldRecomputeFlowPaths.putAll(allFlowPaths);
881 return;
882 }
883
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700884 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800885 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700886 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800887 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
888 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800889
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800890 log.debug("Topology Event: {} {}", eventEntry.eventType(),
891 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800892
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800893 switch (eventEntry.eventType()) {
894 case ENTRY_ADD:
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800895 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800896 break;
897 case ENTRY_REMOVE:
Naoki Shiota9f6fc212014-01-09 21:38:08 -0800898 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800899 break;
900 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700901 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700902 if (isTopologyModified) {
903 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800904 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700905 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800906 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700907
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800908 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800909 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800910 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800911 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800912 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800913 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800914
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700915 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800916 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700917 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800918 if (! unmatchedFlowEntryAdd.isEmpty()) {
919 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
920 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800921 // log.debug("Processing Unmatched Flow Entry: {}",
922 // flowEntry.toString());
923
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800924 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800925 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800926 remainingUpdates.put(flowEntry.flowEntryId().value(),
927 flowEntry);
928 continue;
929 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800930 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
931 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800932 remainingUpdates.put(flowEntry.flowEntryId().value(),
933 flowEntry);
934 continue;
935 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800936 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
937 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
938 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700939 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800940 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700941 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800942 }
943
944 /**
945 * Process the Flow Entry events.
946 */
947 private void processFlowEntryEvents() {
948 FlowPath flowPath;
949 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700950
951 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800952 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700953 //
954 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
955 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800956
957 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800958 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800959
960 if ((! flowEntry.isValidFlowId()) ||
961 (! flowEntry.isValidFlowEntryId())) {
962 continue;
963 }
964
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700965 switch (eventEntry.eventType()) {
966 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800967 flowPath = allFlowPaths.get(flowEntry.flowId().value());
968 if (flowPath == null) {
969 // Flow Path not found: keep the entry for later matching
970 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
971 flowEntry);
972 break;
973 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800974 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
975 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800976 // Flow Entry not found: keep the entry for later matching
977 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
978 flowEntry);
979 break;
980 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800981 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
982 // Add the updated Flow Path to the list of updated paths
983 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
984 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700985 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800986
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700987 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800988 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
989 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800990 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800991 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800992
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800993 flowPath = allFlowPaths.get(flowEntry.flowId().value());
994 if (flowPath == null) {
995 // Flow Path not found: ignore the update
996 break;
997 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800998 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
999 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -08001000 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001001 break;
1002 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001003 if (updateFlowEntryRemove(flowPath, localFlowEntry,
1004 flowEntry)) {
1005 // Add the updated Flow Path to the list of updated paths
1006 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
1007 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001008 break;
1009 }
1010 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001011 }
1012
1013 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001014 * Find a Flow Entry that should be updated because of an external
1015 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001016 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001017 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001018 * @param newFlowEntry the FlowEntry with the new state.
1019 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001020 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001021 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
1022 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001023 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001024 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001025 //
1026 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001027 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001028 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001029 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001030 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001031
1032 //
1033 // Local Flow Entry match found
1034 //
1035 if (localFlowEntry.isValidFlowEntryId()) {
1036 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001037 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001038 //
1039 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001040 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001041 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001042 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001043 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001044 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001045 return localFlowEntry;
1046 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001047
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001048 return null; // Entry not found
1049 }
1050
1051 /**
1052 * Update a Flow Entry because of an external ENTRY_ADD event.
1053 *
1054 * @param flowPath the FlowPath for the Flow Entry to update.
1055 * @param localFlowEntry the local Flow Entry to update.
1056 * @param newFlowEntry the FlowEntry with the new state.
1057 * @return true if the local Flow Entry was updated, otherwise false.
1058 */
1059 private boolean updateFlowEntryAdd(FlowPath flowPath,
1060 FlowEntry localFlowEntry,
1061 FlowEntry newFlowEntry) {
1062 boolean updated = false;
1063
1064 if (localFlowEntry.flowEntryUserState() ==
1065 FlowEntryUserState.FE_USER_DELETE) {
1066 // Don't add-back a Flow Entry that is already deleted
1067 return false;
1068 }
1069
1070 if (! localFlowEntry.isValidFlowEntryId()) {
1071 // Update the Flow Entry ID
1072 FlowEntryId flowEntryId =
1073 new FlowEntryId(newFlowEntry.flowEntryId().value());
1074 localFlowEntry.setFlowEntryId(flowEntryId);
1075 updated = true;
1076 }
1077
1078 //
1079 // Update the local Flow Entry, and keep state to check
1080 // if the Flow Path has been installed.
1081 //
1082 if (localFlowEntry.flowEntryUserState() !=
1083 newFlowEntry.flowEntryUserState()) {
1084 localFlowEntry.setFlowEntryUserState(
1085 newFlowEntry.flowEntryUserState());
1086 updated = true;
1087 }
1088 if (localFlowEntry.flowEntrySwitchState() !=
1089 newFlowEntry.flowEntrySwitchState()) {
1090 localFlowEntry.setFlowEntrySwitchState(
1091 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001092 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001093 updated = true;
1094 }
1095
1096 return updated;
1097 }
1098
1099 /**
1100 * Find a Flow Entry that should be updated because of an external
1101 * ENTRY_REMOVE event.
1102 *
1103 * @param flowPath the FlowPath for the Flow Entry to update.
1104 * @param newFlowEntry the FlowEntry with the new state.
1105 * @return the Flow Entry that should be updated if found, otherwise null.
1106 */
1107 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1108 FlowEntry newFlowEntry) {
1109 //
1110 // Iterate over all Flow Entries and find a match based on
1111 // the Flow Entry ID.
1112 //
1113 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1114 if (! localFlowEntry.isValidFlowEntryId())
1115 continue;
1116 if (localFlowEntry.flowEntryId().value() !=
1117 newFlowEntry.flowEntryId().value()) {
1118 continue;
1119 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001120 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001121 }
1122
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001123 return null; // Entry not found
1124 }
1125
1126 /**
1127 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1128 *
1129 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001130 * @param localFlowEntry the local Flow Entry to update.
1131 * @param newFlowEntry the FlowEntry with the new state.
1132 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001133 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001134 private boolean updateFlowEntryRemove(FlowPath flowPath,
1135 FlowEntry localFlowEntry,
1136 FlowEntry newFlowEntry) {
1137 boolean updated = false;
1138
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001139 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001140 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001141 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001142 if (localFlowEntry.flowEntryUserState() !=
1143 newFlowEntry.flowEntryUserState()) {
1144 localFlowEntry.setFlowEntryUserState(
1145 newFlowEntry.flowEntryUserState());
1146 updated = true;
1147 }
1148 if (localFlowEntry.flowEntrySwitchState() !=
1149 newFlowEntry.flowEntrySwitchState()) {
1150 localFlowEntry.setFlowEntrySwitchState(
1151 newFlowEntry.flowEntrySwitchState());
1152 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001153 }
1154
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001155 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001156 }
1157
1158 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001159 * Recompute a Flow Path.
1160 *
1161 * @param flowPath the Flow Path to recompute.
1162 * @return true if the recomputed Flow Path has changed, otherwise false.
1163 */
1164 private boolean recomputeFlowPath(FlowPath flowPath) {
1165 boolean hasChanged = false;
1166
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001167 if (enableOnrc2014MeasurementsFlows) {
1168 // Cleanup the deleted Flow Entries from the earlier iteration
1169 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001170
1171 //
1172 // TODO: Fake it that the Flow Entries have been already pushed
1173 // into the switches, so we don't push them again.
1174 //
1175 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1176 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1177 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001178 }
1179
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001180 //
1181 // Test whether the Flow Path needs to be recomputed
1182 //
1183 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001184 case FP_TYPE_UNKNOWN:
1185 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001186 case FP_TYPE_SHORTEST_PATH:
1187 break;
1188 case FP_TYPE_EXPLICIT_PATH:
1189 return false; // An explicit path never changes
1190 }
1191
1192 DataPath oldDataPath = flowPath.dataPath();
1193
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001194 // Compute the new path
Naoki Shiota9f6fc212014-01-09 21:38:08 -08001195 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001196 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001197
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001198 if (newDataPath == null) {
1199 // We need the DataPath to compare the paths
1200 newDataPath = new DataPath();
1201 }
1202 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1203
1204 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001205 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001206 //
1207 if (oldDataPath.flowEntries().size() !=
1208 newDataPath.flowEntries().size()) {
1209 hasChanged = true;
1210 } else {
1211 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1212 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1213 while (oldIter.hasNext() && newIter.hasNext()) {
1214 FlowEntry oldFlowEntry = oldIter.next();
1215 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001216 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1217 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001218 hasChanged = true;
1219 break;
1220 }
1221 }
1222 }
1223 if (! hasChanged)
1224 return hasChanged;
1225
1226 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001227 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001228 // - If a Flow Entry for a switch is in the old data path, but not
1229 // in the new data path, then mark it for deletion.
1230 // - If a Flow Entry for a switch is in the new data path, but not
1231 // in the old data path, then mark it for addition.
1232 // - If a Flow Entry for a switch is in both the old and the new
1233 // data path, but it has changed, e.g., the incoming and/or outgoing
1234 // port(s), then mark the old Flow Entry for deletion, and mark
1235 // the new Flow Entry for addition.
1236 // - If a Flow Entry for a switch is in both the old and the new
1237 // data path, and it hasn't changed, then just keep it.
1238 //
1239 // NOTE: We use the Switch DPID of each entry to match the entries
1240 //
1241 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1242 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1243 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1244 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1245
1246 // Prepare maps with the Flow Entries, so they are fast to lookup
1247 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1248 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1249 for (FlowEntry flowEntry : newDataPath.flowEntries())
1250 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1251
1252 //
1253 // Find the old Flow Entries that should be deleted
1254 //
1255 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1256 FlowEntry newFlowEntry =
1257 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1258 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001259 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001260 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1261 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1262 deletedFlowEntries.add(oldFlowEntry);
1263 }
1264 }
1265
1266 //
1267 // Find the new Flow Entries that should be added or updated
1268 //
1269 int idx = 0;
1270 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1271 FlowEntry oldFlowEntry =
1272 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1273
1274 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001275 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1276 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001277 //
1278 // Both Flow Entries are same
1279 //
1280 finalFlowEntries.add(oldFlowEntry);
1281 idx++;
1282 continue;
1283 }
1284
1285 if (oldFlowEntry != null) {
1286 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001287 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001288 //
1289 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1290 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1291 deletedFlowEntries.add(oldFlowEntry);
1292 }
1293
1294 //
1295 // Add the new Flow Entry
1296 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001297 //
1298 // NOTE: Assign only the Flow ID.
1299 // The Flow Entry ID is assigned later only for the Flow Entries
1300 // this instance is responsible for.
1301 //
1302 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001303
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001304 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001305 // Copy the Flow timeouts
1306 //
1307 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1308 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1309
1310 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001311 // Allocate the FlowEntryMatch by copying the default one
1312 // from the FlowPath (if set).
1313 //
1314 FlowEntryMatch flowEntryMatch = null;
1315 if (flowPath.flowEntryMatch() != null)
1316 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1317 else
1318 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001319 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001320
1321 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001322 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1323
1324 //
1325 // Set the actions:
1326 // If the first Flow Entry, copy the Flow Path actions to it.
1327 //
1328 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1329 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1330 FlowEntryActions flowActions =
1331 new FlowEntryActions(flowPath.flowEntryActions());
1332 for (FlowEntryAction action : flowActions.actions())
1333 flowEntryActions.addAction(action);
1334 }
1335 idx++;
1336
1337 //
1338 // Add the outgoing port output action
1339 //
1340 FlowEntryAction flowEntryAction = new FlowEntryAction();
1341 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1342 flowEntryActions.addAction(flowEntryAction);
1343
1344 //
1345 // Set the state of the new Flow Entry
1346 //
1347 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1348 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1349 finalFlowEntries.add(newFlowEntry);
1350 }
1351
1352 //
1353 // Replace the old Flow Entries with the new Flow Entries.
1354 // Note that the Flow Entries that will be deleted are added at
1355 // the end.
1356 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001357 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001358 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1359
1360 return hasChanged;
1361 }
1362
1363 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001364 * Receive a notification that a Flow is added.
1365 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001366 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001367 */
1368 @Override
1369 public void notificationRecvFlowAdded(FlowPath flowPath) {
1370 EventEntry<FlowPath> eventEntry =
1371 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1372 networkEvents.add(eventEntry);
1373 }
1374
1375 /**
1376 * Receive a notification that a Flow is removed.
1377 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001378 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001379 */
1380 @Override
1381 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1382 EventEntry<FlowPath> eventEntry =
1383 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1384 networkEvents.add(eventEntry);
1385 }
1386
1387 /**
1388 * Receive a notification that a Flow is updated.
1389 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001390 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001391 */
1392 @Override
1393 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1394 // NOTE: The ADD and UPDATE events are processed in same way
1395 EventEntry<FlowPath> eventEntry =
1396 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1397 networkEvents.add(eventEntry);
1398 }
1399
1400 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001401 * Receive a notification that a FlowEntry is added.
1402 *
1403 * @param flowEntry the FlowEntry that is added.
1404 */
1405 @Override
1406 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001407 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001408 PerformanceMonitor.start("EventHandler.AddFlowEntryToSwitch");
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001409 Collection entries = new ArrayList();
1410 entries.add(flowEntry);
1411 flowManager.pushModifiedFlowEntriesToSwitches(entries);
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001412 PerformanceMonitor.stop("EventHandler.AddFlowEntryToSwitch");
Pavlin Radoslavov8bd6d112014-01-12 20:12:37 -08001413 PerformanceMonitor.report("EventHandler.AddFlowEntryToSwitch");
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001414 return;
1415 }
1416
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001417 EventEntry<FlowEntry> eventEntry =
1418 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1419 networkEvents.add(eventEntry);
1420 }
1421
1422 /**
1423 * Receive a notification that a FlowEntry is removed.
1424 *
1425 * @param flowEntry the FlowEntry that is removed.
1426 */
1427 @Override
1428 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001429 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001430 PerformanceMonitor.start("EventHandler.RemoveFlowEntryFromSwitch");
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001431 //
1432 // NOTE: Must update the state to DELETE, because
1433 // the notification contains the original state.
1434 //
1435 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1436
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001437 Collection entries = new ArrayList();
1438 entries.add(flowEntry);
1439 flowManager.pushModifiedFlowEntriesToSwitches(entries);
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001440 PerformanceMonitor.stop("EventHandler.RemoveFlowEntryFromSwitch");
Pavlin Radoslavov8bd6d112014-01-12 20:12:37 -08001441 PerformanceMonitor.report("EventHandler.RemoveFlowEntryFromSwitch");
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001442 return;
1443 }
1444
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001445 EventEntry<FlowEntry> eventEntry =
1446 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1447 networkEvents.add(eventEntry);
1448 }
1449
1450 /**
1451 * Receive a notification that a FlowEntry is updated.
1452 *
1453 * @param flowEntry the FlowEntry that is updated.
1454 */
1455 @Override
1456 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001457 if (enableOnrc2014MeasurementsFlows) {
1458 Collection entries = new ArrayList();
1459 entries.add(flowEntry);
1460 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1461 return;
1462 }
1463
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001464 // NOTE: The ADD and UPDATE events are processed in same way
1465 EventEntry<FlowEntry> eventEntry =
1466 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1467 networkEvents.add(eventEntry);
1468 }
1469
1470 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001471 * Receive a notification that a FlowId is added.
1472 *
1473 * @param flowId the FlowId that is added.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001474 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001475 */
1476 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001477 public void notificationRecvFlowIdAdded(FlowId flowId, Dpid dpid) {
1478 Pair flowIdPair = new Pair(flowId, dpid);
1479
1480 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1481 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001482 networkEvents.add(eventEntry);
1483 }
1484
1485 /**
1486 * Receive a notification that a FlowId is removed.
1487 *
1488 * @param flowId the FlowId that is removed.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001489 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001490 */
1491 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001492 public void notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1493 Pair flowIdPair = new Pair(flowId, dpid);
1494
1495 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1496 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001497 networkEvents.add(eventEntry);
1498 }
1499
1500 /**
1501 * Receive a notification that a FlowId is updated.
1502 *
1503 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001504 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001505 */
1506 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001507 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1508 Pair flowIdPair = new Pair(flowId, dpid);
1509
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001510 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001511 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1512 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001513 networkEvents.add(eventEntry);
1514 }
1515
1516 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001517 * Receive a notification that a FlowEntryId is added.
1518 *
1519 * @param flowEntryId the FlowEntryId that is added.
1520 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1521 */
1522 @Override
1523 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1524 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001525 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1526
1527 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1528 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001529 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001530 }
1531
1532 /**
1533 * Receive a notification that a FlowEntryId is removed.
1534 *
1535 * @param flowEntryId the FlowEntryId that is removed.
1536 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1537 */
1538 @Override
1539 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1540 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001541 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1542
1543 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1544 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001545 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001546 }
1547
1548 /**
1549 * Receive a notification that a FlowEntryId is updated.
1550 *
1551 * @param flowEntryId the FlowEntryId that is updated.
1552 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1553 */
1554 @Override
1555 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1556 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001557 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1558
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001559 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001560 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1561 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001562 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001563 }
1564
1565 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001566 * Receive a notification that a Topology Element is added.
1567 *
1568 * @param topologyElement the Topology Element that is added.
1569 */
1570 @Override
1571 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1572 EventEntry<TopologyElement> eventEntry =
1573 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1574 networkEvents.add(eventEntry);
1575 }
1576
1577 /**
1578 * Receive a notification that a Topology Element is removed.
1579 *
1580 * @param topologyElement the Topology Element that is removed.
1581 */
1582 @Override
1583 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1584 EventEntry<TopologyElement> eventEntry =
1585 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1586 networkEvents.add(eventEntry);
1587 }
1588
1589 /**
1590 * Receive a notification that a Topology Element is updated.
1591 *
1592 * @param topologyElement the Topology Element that is updated.
1593 */
1594 @Override
1595 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1596 // NOTE: The ADD and UPDATE events are processed in same way
1597 EventEntry<TopologyElement> eventEntry =
1598 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1599 networkEvents.add(eventEntry);
1600 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001601
1602 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001603 * Receive a notification that a switch is added to this instance.
1604 *
1605 * @param sw the switch that is added.
1606 */
1607 @Override
1608 public void addedSwitch(IOFSwitch sw) {
1609 Dpid dpid = new Dpid(sw.getId());
1610 EventEntry<Dpid> eventEntry =
1611 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1612 networkEvents.add(eventEntry);
1613 }
1614
1615 /**
1616 * Receive a notification that a switch is removed from this instance.
1617 *
1618 * @param sw the switch that is removed.
1619 */
1620 @Override
1621 public void removedSwitch(IOFSwitch sw) {
1622 Dpid dpid = new Dpid(sw.getId());
1623 EventEntry<Dpid> eventEntry =
1624 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1625 networkEvents.add(eventEntry);
1626 }
1627
1628 /**
1629 * Receive a notification that the ports on a switch have changed.
1630 */
1631 @Override
1632 public void switchPortChanged(Long switchId) {
1633 // Nothing to do
1634 }
1635
1636 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001637 * Get a sorted copy of all Flow Paths.
1638 *
1639 * @return a sorted copy of all Flow Paths.
1640 */
1641 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1642 SortedMap<Long, FlowPath> sortedFlowPaths =
1643 new TreeMap<Long, FlowPath>();
1644
1645 //
1646 // TODO: For now we use serialization/deserialization to create
1647 // a copy of each Flow Path. In the future, we should use proper
1648 // copy constructors.
1649 //
1650 Kryo kryo = kryoFactory.newKryo();
1651 synchronized (allFlowPaths) {
1652 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1653 FlowPath origFlowPath = entry.getValue();
1654 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1655 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1656 }
1657 }
1658 kryoFactory.deleteKryo(kryo);
1659
1660 return sortedFlowPaths;
1661 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001662}