blob: 8806572bf2eabefaa42125766456a22797b9c767 [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 }
379 PerformanceMonitor.stop("EventHandler.WriteFlowsToDb");
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");
392 PerformanceMonitor.report();
393
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800394 return;
395 }
396
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700397 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800398 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700399 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700400 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700401
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800402 processFlowPathEvents();
403 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800404 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800405 processFlowEntryEvents();
406
407 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800408 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800409 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800410 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800411 }
412
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800413 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800414 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800415
416 // Assign missing Flow Entry IDs
417 assignFlowEntryId(modifiedFlowEntries);
418
419 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800420 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800421 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800422 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
423 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800424
425 //
426 // Remove Flow Entries that were deleted
427 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800428 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800429 flowPath.dataPath().removeDeletedFlowEntries();
430
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800431 //
432 // Check if Flow Paths have been installed into all switches,
433 // and generate the appropriate events.
434 //
435 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
436
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800437 // Cleanup
438 topologyEvents.clear();
439 flowPathEvents.clear();
440 flowEntryEvents.clear();
441 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800442 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800443 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800444 checkIfInstalledFlowPaths.clear();
445 }
446
447 /**
448 * Check if Flow Paths have been installed into all switches,
449 * and generate the appropriate events.
450 *
451 * @param flowPaths the flowPaths to process.
452 */
453 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
454 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
455
456 Kryo kryo = kryoFactory.newKryo();
457
458 for (FlowPath flowPath : flowPaths) {
459 boolean isInstalled = true;
460
461 //
462 // Check whether all Flow Entries have been installed
463 //
464 for (FlowEntry flowEntry : flowPath.flowEntries()) {
465 if (flowEntry.flowEntrySwitchState() !=
466 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
467 isInstalled = false;
468 break;
469 }
470 }
471
472 if (isInstalled) {
473 // Create a copy and add it to the list
474 FlowPath copyFlowPath = kryo.copy(flowPath);
475 installedFlowPaths.add(copyFlowPath);
476 }
477 }
478 kryoFactory.deleteKryo(kryo);
479
480 // Generate an event for the installed Flow Path.
481 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800482 }
483
484 /**
485 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800486 *
487 * @param modifiedFlowPaths the Flow Paths to process.
488 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800489 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800490 private Collection<FlowEntry> extractModifiedFlowEntries(
491 Collection<FlowPath> modifiedFlowPaths) {
492 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800493
494 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800495 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800496 for (FlowEntry flowEntry : flowPath.flowEntries()) {
497 if (flowEntry.flowEntrySwitchState() ==
498 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800499 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800500 }
501 }
502 }
503 return modifiedFlowEntries;
504 }
505
506 /**
507 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800508 *
509 * @param modifiedFlowEnries the collection of Flow Entries that need
510 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800511 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800512 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800513 if (modifiedFlowEntries.isEmpty())
514 return;
515
516 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
517
518 //
519 // Assign the Flow Entry ID only for Flow Entries for my switches
520 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800521 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800522 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
523 if (mySwitch == null)
524 continue;
525 if (! flowEntry.isValidFlowEntryId()) {
526 long id = flowManager.getNextFlowEntryId();
527 flowEntry.setFlowEntryId(new FlowEntryId(id));
528 }
529 }
530 }
531
532 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800533 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800534 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800535 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800536 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800537 private void fixFlowFromDatabase(FlowPath flowPath) {
538 //
539 // TODO: Bug workaround / fix :
540 // method FlowDatabaseOperation.extractFlowEntry() doesn't
541 // fetch the inPort and outPort, hence we assign them here.
542 //
543 // Assign the inPort and outPort for the Flow Entries
544 for (FlowEntry flowEntry : flowPath.flowEntries()) {
545 // Set the inPort
546 do {
547 if (flowEntry.inPort() != null)
548 break;
549 if (flowEntry.flowEntryMatch() == null)
550 break;
551 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
552 flowEntry.setInPort(inPort);
553 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800554
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800555 // Set the outPort
556 do {
557 if (flowEntry.outPort() != null)
558 break;
559 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
560 if (fa.actionOutput() != null) {
561 Port outPort = new Port(fa.actionOutput().port().value());
562 flowEntry.setOutPort(outPort);
563 break;
564 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800565 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800566 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800567 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800568 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800569
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800570 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800571 * Process the Switch Dpid events.
572 */
573 private void processSwitchDpidEvents() {
574 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
575 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
576
577 //
578 // Process all Switch Dpid events and update the appropriate state
579 //
580 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
581 Dpid dpid = eventEntry.eventData();
582
583 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
584
585 // Compute the final set of added and removed switches
586 switch (eventEntry.eventType()) {
587 case ENTRY_ADD:
588 addedSwitches.put(dpid.value(), dpid);
589 removedSwitches.remove(dpid.value());
590 break;
591 case ENTRY_REMOVE:
592 addedSwitches.remove(dpid.value());
593 removedSwitches.put(dpid.value(), dpid);
594 break;
595 }
596 }
597
598 //
599 // Remove the Flows from the local cache if the removed
600 // switch is the Source Switch.
601 //
602 // TODO: This search can be expensive for a large number of flows
603 // and should be optmized.
604 //
605 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
606 for (Dpid switchDpid : removedSwitches.values()) {
607 for (FlowPath flowPath : allFlowPaths.values()) {
608 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
609 if (srcDpid.value() == switchDpid.value())
610 deleteFlowIds.add(flowPath.flowId());
611 }
612 }
613 //
614 // Remove the Flows from the local cache
615 //
616 for (FlowId flowId : deleteFlowIds)
617 allFlowPaths.remove(flowId.value());
618
619 // Get the Flows for the added switches
620 Collection<FlowPath> flowPaths =
621 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
622 addedSwitches.values());
623 for (FlowPath flowPath : flowPaths) {
624 allFlowPaths.put(flowPath.flowId().value(), flowPath);
625 }
626 }
627
628 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800629 * Process the Flow ID events.
630 *
631 * @param mySwitches the collection of my switches.
632 */
633 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800634 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
635
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800636 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800637 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800638 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800639 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
640 Pair<FlowId, Dpid> pair = eventEntry.eventData();
641 FlowId flowId = pair.first;
642 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800643
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800644 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
645 flowId, dpid);
646
647 //
648 // Ignore Flows if the Source Switch is not controlled by this
649 // instance.
650 //
651 if (mySwitches.get(dpid.value()) == null)
652 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800653
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800654 switch (eventEntry.eventType()) {
655 case ENTRY_ADD: {
656 //
657 // Add a new Flow Path
658 //
659 if (allFlowPaths.get(flowId.value()) != null) {
660 //
661 // TODO: What to do if the Flow Path already exists?
662 // Fow now, we just re-add it.
663 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800664 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800665 shouldFetchMyFlowIds.add(flowId);
666
667 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800668 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800669
670 case ENTRY_REMOVE: {
671 //
672 // Remove an existing Flow Path.
673 //
674 // Find the Flow Path, and mark the Flow and its Flow Entries
675 // for deletion.
676 //
677 FlowPath existingFlowPath =
678 allFlowPaths.get(flowId.value());
679 if (existingFlowPath == null)
680 continue; // Nothing to do
681
682 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
683 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
684 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
685 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
686 }
687
688 // Remove the Flow Path from the internal state
689 Long key = existingFlowPath.flowId().value();
690 allFlowPaths.remove(key);
691 shouldRecomputeFlowPaths.remove(key);
692 modifiedFlowPaths.put(key, existingFlowPath);
693
694 break;
695 }
696 }
697 }
698
699 // Get my Flows
700 Collection<FlowPath> myFlows =
Pavlin Radoslavov6602b6a2014-01-10 16:43:29 -0800701 ParallelFlowDatabaseOperation.getFlows(dbHandler,
702 shouldFetchMyFlowIds);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800703
704 for (FlowPath flowPath : myFlows) {
705 fixFlowFromDatabase(flowPath);
706
707 switch (flowPath.flowPathType()) {
708 case FP_TYPE_SHORTEST_PATH:
709 //
710 // Reset the Data Path, in case it was set already, because
711 // we are going to recompute it anyway.
712 //
713 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800714 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
715 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800716 break;
717 case FP_TYPE_EXPLICIT_PATH:
718 //
719 // Mark all Flow Entries for installation in the switches.
720 //
721 for (FlowEntry flowEntry : flowPath.flowEntries()) {
722 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
723 }
724 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
725 break;
726 case FP_TYPE_UNKNOWN:
727 log.error("FlowPath event with unknown type");
728 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800729 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800730 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800731 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800732 }
733
734 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800735 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800736 *
737 * @param mySwitches the collection of my switches.
738 * @return a collection of modified Flow Entries this instance needs
739 * to push to its own switches.
740 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800741 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800742 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
743
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800744 //
745 // Process all Flow ID events and update the appropriate state
746 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800747 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
748 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
749 FlowEntryId flowEntryId = pair.first;
750 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800751
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800752 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
753 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800754
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800755 if (mySwitches.get(dpid.value()) == null)
756 continue;
757
758 // Fetch the Flow Entry
759 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
760 flowEntryId);
761 if (flowEntry == null) {
762 log.debug("Flow Entry ID {} : Flow Entry not found!",
763 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800764 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800765 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800766 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800767 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800768
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800769 return modifiedFlowEntries;
770 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800771
772 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800773 * Process the Flow Path events.
774 */
775 private void processFlowPathEvents() {
776 //
777 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700778 //
779 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
780 FlowPath flowPath = eventEntry.eventData();
781
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800782 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800783
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700784 switch (eventEntry.eventType()) {
785 case ENTRY_ADD: {
786 //
787 // Add a new Flow Path
788 //
789 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
790 //
791 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800792 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700793 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700794 }
795
796 switch (flowPath.flowPathType()) {
797 case FP_TYPE_SHORTEST_PATH:
798 //
799 // Reset the Data Path, in case it was set already, because
800 // we are going to recompute it anyway.
801 //
802 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800803 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
804 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700805 break;
806 case FP_TYPE_EXPLICIT_PATH:
807 //
808 // Mark all Flow Entries for installation in the switches.
809 //
810 for (FlowEntry flowEntry : flowPath.flowEntries()) {
811 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
812 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800813 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700814 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800815 case FP_TYPE_UNKNOWN:
816 log.error("FlowPath event with unknown type");
817 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700818 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800819 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700820
821 break;
822 }
823
824 case ENTRY_REMOVE: {
825 //
826 // Remove an existing Flow Path.
827 //
828 // Find the Flow Path, and mark the Flow and its Flow Entries
829 // for deletion.
830 //
831 FlowPath existingFlowPath =
832 allFlowPaths.get(flowPath.flowId().value());
833 if (existingFlowPath == null)
834 continue; // Nothing to do
835
836 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
837 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
838 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
839 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
840 }
841
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800842 // Remove the Flow Path from the internal state
843 Long key = existingFlowPath.flowId().value();
844 allFlowPaths.remove(key);
845 shouldRecomputeFlowPaths.remove(key);
846 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700847
848 break;
849 }
850 }
851 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800852 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700853
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800854 /**
855 * Process the Topology events.
856 */
857 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800858 boolean isTopologyModified = false;
859
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800860 if (enableOnrc2014MeasurementsTopology) {
861 if (topologyEvents.isEmpty())
862 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800863
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800864 // TODO: Code for debugging purpose only
865 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
866 TopologyElement topologyElement = eventEntry.eventData();
867 log.debug("Topology Event: {} {}", eventEntry.eventType(),
868 topologyElement.toString());
869 }
870
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800871 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800872 topology.readFromDatabase(dbHandler);
873 log.debug("[AFTER] {}", topology.toString());
874 shouldRecomputeFlowPaths.putAll(allFlowPaths);
875 return;
876 }
877
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700878 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800879 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700880 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800881 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
882 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800883
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800884 log.debug("Topology Event: {} {}", eventEntry.eventType(),
885 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800886
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800887 switch (eventEntry.eventType()) {
888 case ENTRY_ADD:
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800889 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800890 break;
891 case ENTRY_REMOVE:
Naoki Shiota9f6fc212014-01-09 21:38:08 -0800892 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800893 break;
894 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700895 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700896 if (isTopologyModified) {
897 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800898 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700899 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800900 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700901
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800902 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800903 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800904 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800905 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800906 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800907 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800908
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700909 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800910 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700911 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800912 if (! unmatchedFlowEntryAdd.isEmpty()) {
913 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
914 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800915 // log.debug("Processing Unmatched Flow Entry: {}",
916 // flowEntry.toString());
917
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800918 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800919 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800920 remainingUpdates.put(flowEntry.flowEntryId().value(),
921 flowEntry);
922 continue;
923 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800924 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
925 if (localFlowEntry == 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 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
931 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
932 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700933 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800934 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700935 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800936 }
937
938 /**
939 * Process the Flow Entry events.
940 */
941 private void processFlowEntryEvents() {
942 FlowPath flowPath;
943 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700944
945 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800946 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700947 //
948 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
949 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800950
951 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800952 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800953
954 if ((! flowEntry.isValidFlowId()) ||
955 (! flowEntry.isValidFlowEntryId())) {
956 continue;
957 }
958
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700959 switch (eventEntry.eventType()) {
960 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800961 flowPath = allFlowPaths.get(flowEntry.flowId().value());
962 if (flowPath == null) {
963 // Flow Path not found: keep the entry for later matching
964 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
965 flowEntry);
966 break;
967 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800968 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
969 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800970 // Flow Entry not found: keep the entry for later matching
971 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
972 flowEntry);
973 break;
974 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800975 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
976 // Add the updated Flow Path to the list of updated paths
977 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
978 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700979 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800980
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700981 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800982 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
983 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800984 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800985 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800986
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800987 flowPath = allFlowPaths.get(flowEntry.flowId().value());
988 if (flowPath == null) {
989 // Flow Path not found: ignore the update
990 break;
991 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800992 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
993 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800994 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800995 break;
996 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800997 if (updateFlowEntryRemove(flowPath, localFlowEntry,
998 flowEntry)) {
999 // Add the updated Flow Path to the list of updated paths
1000 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
1001 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001002 break;
1003 }
1004 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001005 }
1006
1007 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001008 * Find a Flow Entry that should be updated because of an external
1009 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001010 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001011 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001012 * @param newFlowEntry the FlowEntry with the new state.
1013 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001014 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001015 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
1016 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001017 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001018 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001019 //
1020 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001021 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001022 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001023 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001024 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001025
1026 //
1027 // Local Flow Entry match found
1028 //
1029 if (localFlowEntry.isValidFlowEntryId()) {
1030 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001031 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001032 //
1033 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001034 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001035 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001036 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001037 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001038 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001039 return localFlowEntry;
1040 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001041
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001042 return null; // Entry not found
1043 }
1044
1045 /**
1046 * Update a Flow Entry because of an external ENTRY_ADD event.
1047 *
1048 * @param flowPath the FlowPath for the Flow Entry to update.
1049 * @param localFlowEntry the local Flow Entry to update.
1050 * @param newFlowEntry the FlowEntry with the new state.
1051 * @return true if the local Flow Entry was updated, otherwise false.
1052 */
1053 private boolean updateFlowEntryAdd(FlowPath flowPath,
1054 FlowEntry localFlowEntry,
1055 FlowEntry newFlowEntry) {
1056 boolean updated = false;
1057
1058 if (localFlowEntry.flowEntryUserState() ==
1059 FlowEntryUserState.FE_USER_DELETE) {
1060 // Don't add-back a Flow Entry that is already deleted
1061 return false;
1062 }
1063
1064 if (! localFlowEntry.isValidFlowEntryId()) {
1065 // Update the Flow Entry ID
1066 FlowEntryId flowEntryId =
1067 new FlowEntryId(newFlowEntry.flowEntryId().value());
1068 localFlowEntry.setFlowEntryId(flowEntryId);
1069 updated = true;
1070 }
1071
1072 //
1073 // Update the local Flow Entry, and keep state to check
1074 // if the Flow Path has been installed.
1075 //
1076 if (localFlowEntry.flowEntryUserState() !=
1077 newFlowEntry.flowEntryUserState()) {
1078 localFlowEntry.setFlowEntryUserState(
1079 newFlowEntry.flowEntryUserState());
1080 updated = true;
1081 }
1082 if (localFlowEntry.flowEntrySwitchState() !=
1083 newFlowEntry.flowEntrySwitchState()) {
1084 localFlowEntry.setFlowEntrySwitchState(
1085 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001086 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001087 updated = true;
1088 }
1089
1090 return updated;
1091 }
1092
1093 /**
1094 * Find a Flow Entry that should be updated because of an external
1095 * ENTRY_REMOVE event.
1096 *
1097 * @param flowPath the FlowPath for the Flow Entry to update.
1098 * @param newFlowEntry the FlowEntry with the new state.
1099 * @return the Flow Entry that should be updated if found, otherwise null.
1100 */
1101 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1102 FlowEntry newFlowEntry) {
1103 //
1104 // Iterate over all Flow Entries and find a match based on
1105 // the Flow Entry ID.
1106 //
1107 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1108 if (! localFlowEntry.isValidFlowEntryId())
1109 continue;
1110 if (localFlowEntry.flowEntryId().value() !=
1111 newFlowEntry.flowEntryId().value()) {
1112 continue;
1113 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001114 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001115 }
1116
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001117 return null; // Entry not found
1118 }
1119
1120 /**
1121 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1122 *
1123 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001124 * @param localFlowEntry the local Flow Entry to update.
1125 * @param newFlowEntry the FlowEntry with the new state.
1126 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001127 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001128 private boolean updateFlowEntryRemove(FlowPath flowPath,
1129 FlowEntry localFlowEntry,
1130 FlowEntry newFlowEntry) {
1131 boolean updated = false;
1132
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001133 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001134 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001135 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001136 if (localFlowEntry.flowEntryUserState() !=
1137 newFlowEntry.flowEntryUserState()) {
1138 localFlowEntry.setFlowEntryUserState(
1139 newFlowEntry.flowEntryUserState());
1140 updated = true;
1141 }
1142 if (localFlowEntry.flowEntrySwitchState() !=
1143 newFlowEntry.flowEntrySwitchState()) {
1144 localFlowEntry.setFlowEntrySwitchState(
1145 newFlowEntry.flowEntrySwitchState());
1146 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001147 }
1148
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001149 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001150 }
1151
1152 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001153 * Recompute a Flow Path.
1154 *
1155 * @param flowPath the Flow Path to recompute.
1156 * @return true if the recomputed Flow Path has changed, otherwise false.
1157 */
1158 private boolean recomputeFlowPath(FlowPath flowPath) {
1159 boolean hasChanged = false;
1160
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001161 if (enableOnrc2014MeasurementsFlows) {
1162 // Cleanup the deleted Flow Entries from the earlier iteration
1163 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001164
1165 //
1166 // TODO: Fake it that the Flow Entries have been already pushed
1167 // into the switches, so we don't push them again.
1168 //
1169 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1170 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1171 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001172 }
1173
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001174 //
1175 // Test whether the Flow Path needs to be recomputed
1176 //
1177 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001178 case FP_TYPE_UNKNOWN:
1179 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001180 case FP_TYPE_SHORTEST_PATH:
1181 break;
1182 case FP_TYPE_EXPLICIT_PATH:
1183 return false; // An explicit path never changes
1184 }
1185
1186 DataPath oldDataPath = flowPath.dataPath();
1187
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001188 // Compute the new path
Naoki Shiota9f6fc212014-01-09 21:38:08 -08001189 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001190 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001191
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001192 if (newDataPath == null) {
1193 // We need the DataPath to compare the paths
1194 newDataPath = new DataPath();
1195 }
1196 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1197
1198 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001199 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001200 //
1201 if (oldDataPath.flowEntries().size() !=
1202 newDataPath.flowEntries().size()) {
1203 hasChanged = true;
1204 } else {
1205 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1206 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1207 while (oldIter.hasNext() && newIter.hasNext()) {
1208 FlowEntry oldFlowEntry = oldIter.next();
1209 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001210 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1211 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001212 hasChanged = true;
1213 break;
1214 }
1215 }
1216 }
1217 if (! hasChanged)
1218 return hasChanged;
1219
1220 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001221 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001222 // - If a Flow Entry for a switch is in the old data path, but not
1223 // in the new data path, then mark it for deletion.
1224 // - If a Flow Entry for a switch is in the new data path, but not
1225 // in the old data path, then mark it for addition.
1226 // - If a Flow Entry for a switch is in both the old and the new
1227 // data path, but it has changed, e.g., the incoming and/or outgoing
1228 // port(s), then mark the old Flow Entry for deletion, and mark
1229 // the new Flow Entry for addition.
1230 // - If a Flow Entry for a switch is in both the old and the new
1231 // data path, and it hasn't changed, then just keep it.
1232 //
1233 // NOTE: We use the Switch DPID of each entry to match the entries
1234 //
1235 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1236 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1237 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1238 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1239
1240 // Prepare maps with the Flow Entries, so they are fast to lookup
1241 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1242 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1243 for (FlowEntry flowEntry : newDataPath.flowEntries())
1244 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1245
1246 //
1247 // Find the old Flow Entries that should be deleted
1248 //
1249 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1250 FlowEntry newFlowEntry =
1251 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1252 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001253 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001254 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1255 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1256 deletedFlowEntries.add(oldFlowEntry);
1257 }
1258 }
1259
1260 //
1261 // Find the new Flow Entries that should be added or updated
1262 //
1263 int idx = 0;
1264 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1265 FlowEntry oldFlowEntry =
1266 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1267
1268 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001269 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1270 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001271 //
1272 // Both Flow Entries are same
1273 //
1274 finalFlowEntries.add(oldFlowEntry);
1275 idx++;
1276 continue;
1277 }
1278
1279 if (oldFlowEntry != null) {
1280 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001281 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001282 //
1283 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1284 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1285 deletedFlowEntries.add(oldFlowEntry);
1286 }
1287
1288 //
1289 // Add the new Flow Entry
1290 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001291 //
1292 // NOTE: Assign only the Flow ID.
1293 // The Flow Entry ID is assigned later only for the Flow Entries
1294 // this instance is responsible for.
1295 //
1296 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001297
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001298 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001299 // Copy the Flow timeouts
1300 //
1301 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1302 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1303
1304 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001305 // Allocate the FlowEntryMatch by copying the default one
1306 // from the FlowPath (if set).
1307 //
1308 FlowEntryMatch flowEntryMatch = null;
1309 if (flowPath.flowEntryMatch() != null)
1310 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1311 else
1312 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001313 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001314
1315 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001316 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1317
1318 //
1319 // Set the actions:
1320 // If the first Flow Entry, copy the Flow Path actions to it.
1321 //
1322 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1323 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1324 FlowEntryActions flowActions =
1325 new FlowEntryActions(flowPath.flowEntryActions());
1326 for (FlowEntryAction action : flowActions.actions())
1327 flowEntryActions.addAction(action);
1328 }
1329 idx++;
1330
1331 //
1332 // Add the outgoing port output action
1333 //
1334 FlowEntryAction flowEntryAction = new FlowEntryAction();
1335 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1336 flowEntryActions.addAction(flowEntryAction);
1337
1338 //
1339 // Set the state of the new Flow Entry
1340 //
1341 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1342 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1343 finalFlowEntries.add(newFlowEntry);
1344 }
1345
1346 //
1347 // Replace the old Flow Entries with the new Flow Entries.
1348 // Note that the Flow Entries that will be deleted are added at
1349 // the end.
1350 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001351 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001352 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1353
1354 return hasChanged;
1355 }
1356
1357 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001358 * Receive a notification that a Flow is added.
1359 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001360 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001361 */
1362 @Override
1363 public void notificationRecvFlowAdded(FlowPath flowPath) {
1364 EventEntry<FlowPath> eventEntry =
1365 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1366 networkEvents.add(eventEntry);
1367 }
1368
1369 /**
1370 * Receive a notification that a Flow is removed.
1371 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001372 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001373 */
1374 @Override
1375 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1376 EventEntry<FlowPath> eventEntry =
1377 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1378 networkEvents.add(eventEntry);
1379 }
1380
1381 /**
1382 * Receive a notification that a Flow is updated.
1383 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001384 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001385 */
1386 @Override
1387 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1388 // NOTE: The ADD and UPDATE events are processed in same way
1389 EventEntry<FlowPath> eventEntry =
1390 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1391 networkEvents.add(eventEntry);
1392 }
1393
1394 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001395 * Receive a notification that a FlowEntry is added.
1396 *
1397 * @param flowEntry the FlowEntry that is added.
1398 */
1399 @Override
1400 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001401 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001402 PerformanceMonitor.start("EventHandler.AddFlowEntryToSwitch");
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001403 Collection entries = new ArrayList();
1404 entries.add(flowEntry);
1405 flowManager.pushModifiedFlowEntriesToSwitches(entries);
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001406 PerformanceMonitor.stop("EventHandler.AddFlowEntryToSwitch");
1407 PerformanceMonitor.report();
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001408 return;
1409 }
1410
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001411 EventEntry<FlowEntry> eventEntry =
1412 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1413 networkEvents.add(eventEntry);
1414 }
1415
1416 /**
1417 * Receive a notification that a FlowEntry is removed.
1418 *
1419 * @param flowEntry the FlowEntry that is removed.
1420 */
1421 @Override
1422 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001423 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001424 PerformanceMonitor.start("EventHandler.RemoveFlowEntryFromSwitch");
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001425 //
1426 // NOTE: Must update the state to DELETE, because
1427 // the notification contains the original state.
1428 //
1429 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1430
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001431 Collection entries = new ArrayList();
1432 entries.add(flowEntry);
1433 flowManager.pushModifiedFlowEntriesToSwitches(entries);
Pavlin Radoslavove2497672014-01-12 18:03:35 -08001434 PerformanceMonitor.stop("EventHandler.RemoveFlowEntryFromSwitch");
1435 PerformanceMonitor.report();
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001436 return;
1437 }
1438
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001439 EventEntry<FlowEntry> eventEntry =
1440 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1441 networkEvents.add(eventEntry);
1442 }
1443
1444 /**
1445 * Receive a notification that a FlowEntry is updated.
1446 *
1447 * @param flowEntry the FlowEntry that is updated.
1448 */
1449 @Override
1450 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001451 if (enableOnrc2014MeasurementsFlows) {
1452 Collection entries = new ArrayList();
1453 entries.add(flowEntry);
1454 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1455 return;
1456 }
1457
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001458 // NOTE: The ADD and UPDATE events are processed in same way
1459 EventEntry<FlowEntry> eventEntry =
1460 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1461 networkEvents.add(eventEntry);
1462 }
1463
1464 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001465 * Receive a notification that a FlowId is added.
1466 *
1467 * @param flowId the FlowId that is added.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001468 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001469 */
1470 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001471 public void notificationRecvFlowIdAdded(FlowId flowId, Dpid dpid) {
1472 Pair flowIdPair = new Pair(flowId, dpid);
1473
1474 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1475 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001476 networkEvents.add(eventEntry);
1477 }
1478
1479 /**
1480 * Receive a notification that a FlowId is removed.
1481 *
1482 * @param flowId the FlowId that is removed.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001483 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001484 */
1485 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001486 public void notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1487 Pair flowIdPair = new Pair(flowId, dpid);
1488
1489 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1490 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001491 networkEvents.add(eventEntry);
1492 }
1493
1494 /**
1495 * Receive a notification that a FlowId is updated.
1496 *
1497 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001498 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001499 */
1500 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001501 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1502 Pair flowIdPair = new Pair(flowId, dpid);
1503
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001504 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001505 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1506 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001507 networkEvents.add(eventEntry);
1508 }
1509
1510 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001511 * Receive a notification that a FlowEntryId is added.
1512 *
1513 * @param flowEntryId the FlowEntryId that is added.
1514 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1515 */
1516 @Override
1517 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1518 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001519 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1520
1521 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1522 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001523 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001524 }
1525
1526 /**
1527 * Receive a notification that a FlowEntryId is removed.
1528 *
1529 * @param flowEntryId the FlowEntryId that is removed.
1530 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1531 */
1532 @Override
1533 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1534 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001535 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1536
1537 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1538 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001539 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001540 }
1541
1542 /**
1543 * Receive a notification that a FlowEntryId is updated.
1544 *
1545 * @param flowEntryId the FlowEntryId that is updated.
1546 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1547 */
1548 @Override
1549 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1550 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001551 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1552
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001553 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001554 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1555 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001556 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001557 }
1558
1559 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001560 * Receive a notification that a Topology Element is added.
1561 *
1562 * @param topologyElement the Topology Element that is added.
1563 */
1564 @Override
1565 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1566 EventEntry<TopologyElement> eventEntry =
1567 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1568 networkEvents.add(eventEntry);
1569 }
1570
1571 /**
1572 * Receive a notification that a Topology Element is removed.
1573 *
1574 * @param topologyElement the Topology Element that is removed.
1575 */
1576 @Override
1577 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1578 EventEntry<TopologyElement> eventEntry =
1579 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1580 networkEvents.add(eventEntry);
1581 }
1582
1583 /**
1584 * Receive a notification that a Topology Element is updated.
1585 *
1586 * @param topologyElement the Topology Element that is updated.
1587 */
1588 @Override
1589 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1590 // NOTE: The ADD and UPDATE events are processed in same way
1591 EventEntry<TopologyElement> eventEntry =
1592 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1593 networkEvents.add(eventEntry);
1594 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001595
1596 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001597 * Receive a notification that a switch is added to this instance.
1598 *
1599 * @param sw the switch that is added.
1600 */
1601 @Override
1602 public void addedSwitch(IOFSwitch sw) {
1603 Dpid dpid = new Dpid(sw.getId());
1604 EventEntry<Dpid> eventEntry =
1605 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1606 networkEvents.add(eventEntry);
1607 }
1608
1609 /**
1610 * Receive a notification that a switch is removed from this instance.
1611 *
1612 * @param sw the switch that is removed.
1613 */
1614 @Override
1615 public void removedSwitch(IOFSwitch sw) {
1616 Dpid dpid = new Dpid(sw.getId());
1617 EventEntry<Dpid> eventEntry =
1618 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1619 networkEvents.add(eventEntry);
1620 }
1621
1622 /**
1623 * Receive a notification that the ports on a switch have changed.
1624 */
1625 @Override
1626 public void switchPortChanged(Long switchId) {
1627 // Nothing to do
1628 }
1629
1630 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001631 * Get a sorted copy of all Flow Paths.
1632 *
1633 * @return a sorted copy of all Flow Paths.
1634 */
1635 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1636 SortedMap<Long, FlowPath> sortedFlowPaths =
1637 new TreeMap<Long, FlowPath>();
1638
1639 //
1640 // TODO: For now we use serialization/deserialization to create
1641 // a copy of each Flow Path. In the future, we should use proper
1642 // copy constructors.
1643 //
1644 Kryo kryo = kryoFactory.newKryo();
1645 synchronized (allFlowPaths) {
1646 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1647 FlowPath origFlowPath = entry.getValue();
1648 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1649 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1650 }
1651 }
1652 kryoFactory.deleteKryo(kryo);
1653
1654 return sortedFlowPaths;
1655 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001656}