blob: 931bdd18b60c6678a2713ce84cc63854b62dd1d8 [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 Radoslavovcc757162014-01-10 16:26:38 -0800289 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty() &&
290 switchDpidEvents.isEmpty()) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800291 return; // Nothing to do
292 }
293
294 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
295
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800296 // Process the Switch Dpid events
297 processSwitchDpidEvents();
298
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800299 // Process the Flow ID events
300 processFlowIdEvents(mySwitches);
301
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800302 // Fetch the topology
303 processTopologyEvents();
304
305 // Recompute all affected Flow Paths and keep only the modified
306 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
307 if (recomputeFlowPath(flowPath))
308 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
309 }
310
311 // Assign the Flow Entry ID as needed
312 for (FlowPath flowPath : modifiedFlowPaths.values()) {
313 for (FlowEntry flowEntry : flowPath.flowEntries()) {
314 if (! flowEntry.isValidFlowEntryId()) {
315 long id = flowManager.getNextFlowEntryId();
316 flowEntry.setFlowEntryId(new FlowEntryId(id));
317 }
318 }
319 }
320
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800321 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800322 // Push the modified state to the database
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800323 //
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800324 for (FlowPath flowPath : modifiedFlowPaths.values()) {
325 //
326 // Delete the Flow Path from the Network Map
327 //
328 if (flowPath.flowPathUserState() ==
329 FlowPathUserState.FP_USER_DELETE) {
330 log.debug("Deleting Flow Path From Database: {}", flowPath);
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800331 // TODO: For now the deleting of a Flow Path is blocking
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800332 ParallelFlowDatabaseOperation.deleteFlow(dbHandler,
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800333 flowPath.flowId());
334 // Send the notifications for the deleted Flow Entries
335 for (FlowEntry flowEntry : flowPath.flowEntries()) {
336 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
337 }
338
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800339 continue;
340 }
341
342 log.debug("Pushing Flow Path To Database: {}", flowPath);
343 //
344 // Write the Flow Path to the Network Map
345 //
346 ParallelFlowDatabaseOperation.addFlow(dbHandler, flowPath,
347 datagridService);
348 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800349
350 // Cleanup
351 topologyEvents.clear();
352 flowIdEvents.clear();
Pavlin Radoslavov2d6e5f12014-01-10 16:34:05 -0800353 switchDpidEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800354 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800355 // NOTE: Keep a cache with my Flow Paths
356 // allFlowPaths.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800357 shouldRecomputeFlowPaths.clear();
358 modifiedFlowPaths.clear();
359
360 return;
361 }
362
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700363 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800364 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700365 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700366 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700367
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800368 processFlowPathEvents();
369 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800370 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800371 processFlowEntryEvents();
372
373 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800374 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800375 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800376 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800377 }
378
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800379 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800380 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800381
382 // Assign missing Flow Entry IDs
383 assignFlowEntryId(modifiedFlowEntries);
384
385 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800386 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800387 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800388 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
389 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800390
391 //
392 // Remove Flow Entries that were deleted
393 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800394 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800395 flowPath.dataPath().removeDeletedFlowEntries();
396
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800397 //
398 // Check if Flow Paths have been installed into all switches,
399 // and generate the appropriate events.
400 //
401 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
402
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800403 // Cleanup
404 topologyEvents.clear();
405 flowPathEvents.clear();
406 flowEntryEvents.clear();
407 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800408 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800409 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800410 checkIfInstalledFlowPaths.clear();
411 }
412
413 /**
414 * Check if Flow Paths have been installed into all switches,
415 * and generate the appropriate events.
416 *
417 * @param flowPaths the flowPaths to process.
418 */
419 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
420 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
421
422 Kryo kryo = kryoFactory.newKryo();
423
424 for (FlowPath flowPath : flowPaths) {
425 boolean isInstalled = true;
426
427 //
428 // Check whether all Flow Entries have been installed
429 //
430 for (FlowEntry flowEntry : flowPath.flowEntries()) {
431 if (flowEntry.flowEntrySwitchState() !=
432 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
433 isInstalled = false;
434 break;
435 }
436 }
437
438 if (isInstalled) {
439 // Create a copy and add it to the list
440 FlowPath copyFlowPath = kryo.copy(flowPath);
441 installedFlowPaths.add(copyFlowPath);
442 }
443 }
444 kryoFactory.deleteKryo(kryo);
445
446 // Generate an event for the installed Flow Path.
447 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800448 }
449
450 /**
451 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800452 *
453 * @param modifiedFlowPaths the Flow Paths to process.
454 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800455 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800456 private Collection<FlowEntry> extractModifiedFlowEntries(
457 Collection<FlowPath> modifiedFlowPaths) {
458 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800459
460 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800461 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800462 for (FlowEntry flowEntry : flowPath.flowEntries()) {
463 if (flowEntry.flowEntrySwitchState() ==
464 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800465 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800466 }
467 }
468 }
469 return modifiedFlowEntries;
470 }
471
472 /**
473 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800474 *
475 * @param modifiedFlowEnries the collection of Flow Entries that need
476 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800477 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800478 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800479 if (modifiedFlowEntries.isEmpty())
480 return;
481
482 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
483
484 //
485 // Assign the Flow Entry ID only for Flow Entries for my switches
486 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800487 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800488 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
489 if (mySwitch == null)
490 continue;
491 if (! flowEntry.isValidFlowEntryId()) {
492 long id = flowManager.getNextFlowEntryId();
493 flowEntry.setFlowEntryId(new FlowEntryId(id));
494 }
495 }
496 }
497
498 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800499 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800500 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800501 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800502 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800503 private void fixFlowFromDatabase(FlowPath flowPath) {
504 //
505 // TODO: Bug workaround / fix :
506 // method FlowDatabaseOperation.extractFlowEntry() doesn't
507 // fetch the inPort and outPort, hence we assign them here.
508 //
509 // Assign the inPort and outPort for the Flow Entries
510 for (FlowEntry flowEntry : flowPath.flowEntries()) {
511 // Set the inPort
512 do {
513 if (flowEntry.inPort() != null)
514 break;
515 if (flowEntry.flowEntryMatch() == null)
516 break;
517 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
518 flowEntry.setInPort(inPort);
519 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800520
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800521 // Set the outPort
522 do {
523 if (flowEntry.outPort() != null)
524 break;
525 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
526 if (fa.actionOutput() != null) {
527 Port outPort = new Port(fa.actionOutput().port().value());
528 flowEntry.setOutPort(outPort);
529 break;
530 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800531 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800532 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800533 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800534 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800535
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800536 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800537 * Process the Switch Dpid events.
538 */
539 private void processSwitchDpidEvents() {
540 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
541 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
542
543 //
544 // Process all Switch Dpid events and update the appropriate state
545 //
546 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
547 Dpid dpid = eventEntry.eventData();
548
549 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
550
551 // Compute the final set of added and removed switches
552 switch (eventEntry.eventType()) {
553 case ENTRY_ADD:
554 addedSwitches.put(dpid.value(), dpid);
555 removedSwitches.remove(dpid.value());
556 break;
557 case ENTRY_REMOVE:
558 addedSwitches.remove(dpid.value());
559 removedSwitches.put(dpid.value(), dpid);
560 break;
561 }
562 }
563
564 //
565 // Remove the Flows from the local cache if the removed
566 // switch is the Source Switch.
567 //
568 // TODO: This search can be expensive for a large number of flows
569 // and should be optmized.
570 //
571 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
572 for (Dpid switchDpid : removedSwitches.values()) {
573 for (FlowPath flowPath : allFlowPaths.values()) {
574 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
575 if (srcDpid.value() == switchDpid.value())
576 deleteFlowIds.add(flowPath.flowId());
577 }
578 }
579 //
580 // Remove the Flows from the local cache
581 //
582 for (FlowId flowId : deleteFlowIds)
583 allFlowPaths.remove(flowId.value());
584
585 // Get the Flows for the added switches
586 Collection<FlowPath> flowPaths =
587 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
588 addedSwitches.values());
589 for (FlowPath flowPath : flowPaths) {
590 allFlowPaths.put(flowPath.flowId().value(), flowPath);
591 }
592 }
593
594 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800595 * Process the Flow ID events.
596 *
597 * @param mySwitches the collection of my switches.
598 */
599 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800600 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
601
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800602 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800603 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800604 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800605 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
606 Pair<FlowId, Dpid> pair = eventEntry.eventData();
607 FlowId flowId = pair.first;
608 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800609
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800610 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
611 flowId, dpid);
612
613 //
614 // Ignore Flows if the Source Switch is not controlled by this
615 // instance.
616 //
617 if (mySwitches.get(dpid.value()) == null)
618 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800619
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800620 switch (eventEntry.eventType()) {
621 case ENTRY_ADD: {
622 //
623 // Add a new Flow Path
624 //
625 if (allFlowPaths.get(flowId.value()) != null) {
626 //
627 // TODO: What to do if the Flow Path already exists?
628 // Fow now, we just re-add it.
629 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800630 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800631 shouldFetchMyFlowIds.add(flowId);
632
633 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800634 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800635
636 case ENTRY_REMOVE: {
637 //
638 // Remove an existing Flow Path.
639 //
640 // Find the Flow Path, and mark the Flow and its Flow Entries
641 // for deletion.
642 //
643 FlowPath existingFlowPath =
644 allFlowPaths.get(flowId.value());
645 if (existingFlowPath == null)
646 continue; // Nothing to do
647
648 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
649 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
650 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
651 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
652 }
653
654 // Remove the Flow Path from the internal state
655 Long key = existingFlowPath.flowId().value();
656 allFlowPaths.remove(key);
657 shouldRecomputeFlowPaths.remove(key);
658 modifiedFlowPaths.put(key, existingFlowPath);
659
660 break;
661 }
662 }
663 }
664
665 // Get my Flows
666 Collection<FlowPath> myFlows =
Pavlin Radoslavov6602b6a2014-01-10 16:43:29 -0800667 ParallelFlowDatabaseOperation.getFlows(dbHandler,
668 shouldFetchMyFlowIds);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800669
670 for (FlowPath flowPath : myFlows) {
671 fixFlowFromDatabase(flowPath);
672
673 switch (flowPath.flowPathType()) {
674 case FP_TYPE_SHORTEST_PATH:
675 //
676 // Reset the Data Path, in case it was set already, because
677 // we are going to recompute it anyway.
678 //
679 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800680 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
681 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800682 break;
683 case FP_TYPE_EXPLICIT_PATH:
684 //
685 // Mark all Flow Entries for installation in the switches.
686 //
687 for (FlowEntry flowEntry : flowPath.flowEntries()) {
688 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
689 }
690 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
691 break;
692 case FP_TYPE_UNKNOWN:
693 log.error("FlowPath event with unknown type");
694 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800695 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800696 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800697 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800698 }
699
700 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800701 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800702 *
703 * @param mySwitches the collection of my switches.
704 * @return a collection of modified Flow Entries this instance needs
705 * to push to its own switches.
706 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800707 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800708 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
709
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800710 //
711 // Process all Flow ID events and update the appropriate state
712 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800713 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
714 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
715 FlowEntryId flowEntryId = pair.first;
716 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800717
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800718 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
719 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800720
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800721 if (mySwitches.get(dpid.value()) == null)
722 continue;
723
724 // Fetch the Flow Entry
725 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
726 flowEntryId);
727 if (flowEntry == null) {
728 log.debug("Flow Entry ID {} : Flow Entry not found!",
729 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800730 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800731 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800732 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800733 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800734
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800735 return modifiedFlowEntries;
736 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800737
738 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800739 * Process the Flow Path events.
740 */
741 private void processFlowPathEvents() {
742 //
743 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700744 //
745 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
746 FlowPath flowPath = eventEntry.eventData();
747
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800748 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800749
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700750 switch (eventEntry.eventType()) {
751 case ENTRY_ADD: {
752 //
753 // Add a new Flow Path
754 //
755 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
756 //
757 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800758 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700759 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700760 }
761
762 switch (flowPath.flowPathType()) {
763 case FP_TYPE_SHORTEST_PATH:
764 //
765 // Reset the Data Path, in case it was set already, because
766 // we are going to recompute it anyway.
767 //
768 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800769 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
770 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700771 break;
772 case FP_TYPE_EXPLICIT_PATH:
773 //
774 // Mark all Flow Entries for installation in the switches.
775 //
776 for (FlowEntry flowEntry : flowPath.flowEntries()) {
777 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
778 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800779 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700780 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800781 case FP_TYPE_UNKNOWN:
782 log.error("FlowPath event with unknown type");
783 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700784 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800785 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700786
787 break;
788 }
789
790 case ENTRY_REMOVE: {
791 //
792 // Remove an existing Flow Path.
793 //
794 // Find the Flow Path, and mark the Flow and its Flow Entries
795 // for deletion.
796 //
797 FlowPath existingFlowPath =
798 allFlowPaths.get(flowPath.flowId().value());
799 if (existingFlowPath == null)
800 continue; // Nothing to do
801
802 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
803 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
804 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
805 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
806 }
807
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800808 // Remove the Flow Path from the internal state
809 Long key = existingFlowPath.flowId().value();
810 allFlowPaths.remove(key);
811 shouldRecomputeFlowPaths.remove(key);
812 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700813
814 break;
815 }
816 }
817 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800818 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700819
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800820 /**
821 * Process the Topology events.
822 */
823 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800824 boolean isTopologyModified = false;
825
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800826 if (enableOnrc2014MeasurementsTopology) {
827 if (topologyEvents.isEmpty())
828 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800829
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800830 // TODO: Code for debugging purpose only
831 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
832 TopologyElement topologyElement = eventEntry.eventData();
833 log.debug("Topology Event: {} {}", eventEntry.eventType(),
834 topologyElement.toString());
835 }
836
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800837 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800838 topology.readFromDatabase(dbHandler);
839 log.debug("[AFTER] {}", topology.toString());
840 shouldRecomputeFlowPaths.putAll(allFlowPaths);
841 return;
842 }
843
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700844 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800845 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700846 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800847 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
848 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800849
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800850 log.debug("Topology Event: {} {}", eventEntry.eventType(),
851 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800852
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800853 switch (eventEntry.eventType()) {
854 case ENTRY_ADD:
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800855 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800856 break;
857 case ENTRY_REMOVE:
Naoki Shiota9f6fc212014-01-09 21:38:08 -0800858 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800859 break;
860 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700861 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700862 if (isTopologyModified) {
863 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800864 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700865 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800866 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700867
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800868 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800869 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800870 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800871 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800872 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800873 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800874
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700875 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800876 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700877 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800878 if (! unmatchedFlowEntryAdd.isEmpty()) {
879 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
880 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800881 // log.debug("Processing Unmatched Flow Entry: {}",
882 // flowEntry.toString());
883
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800884 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800885 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800886 remainingUpdates.put(flowEntry.flowEntryId().value(),
887 flowEntry);
888 continue;
889 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800890 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
891 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800892 remainingUpdates.put(flowEntry.flowEntryId().value(),
893 flowEntry);
894 continue;
895 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800896 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
897 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
898 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700899 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800900 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700901 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800902 }
903
904 /**
905 * Process the Flow Entry events.
906 */
907 private void processFlowEntryEvents() {
908 FlowPath flowPath;
909 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700910
911 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800912 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700913 //
914 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
915 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800916
917 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800918 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800919
920 if ((! flowEntry.isValidFlowId()) ||
921 (! flowEntry.isValidFlowEntryId())) {
922 continue;
923 }
924
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700925 switch (eventEntry.eventType()) {
926 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800927 flowPath = allFlowPaths.get(flowEntry.flowId().value());
928 if (flowPath == null) {
929 // Flow Path not found: keep the entry for later matching
930 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
931 flowEntry);
932 break;
933 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800934 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
935 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800936 // Flow Entry not found: keep the entry for later matching
937 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
938 flowEntry);
939 break;
940 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800941 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
942 // Add the updated Flow Path to the list of updated paths
943 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
944 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700945 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800946
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700947 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800948 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
949 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800950 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800951 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800952
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800953 flowPath = allFlowPaths.get(flowEntry.flowId().value());
954 if (flowPath == null) {
955 // Flow Path not found: ignore the update
956 break;
957 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800958 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
959 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800960 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800961 break;
962 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800963 if (updateFlowEntryRemove(flowPath, localFlowEntry,
964 flowEntry)) {
965 // Add the updated Flow Path to the list of updated paths
966 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
967 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700968 break;
969 }
970 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700971 }
972
973 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800974 * Find a Flow Entry that should be updated because of an external
975 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700976 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800977 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800978 * @param newFlowEntry the FlowEntry with the new state.
979 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700980 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800981 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
982 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700983 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800984 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700985 //
986 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800987 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800988 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700989 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800990 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700991
992 //
993 // Local Flow Entry match found
994 //
995 if (localFlowEntry.isValidFlowEntryId()) {
996 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800997 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700998 //
999 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001000 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001001 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001002 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001003 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001004 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001005 return localFlowEntry;
1006 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001007
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001008 return null; // Entry not found
1009 }
1010
1011 /**
1012 * Update a Flow Entry because of an external ENTRY_ADD event.
1013 *
1014 * @param flowPath the FlowPath for the Flow Entry to update.
1015 * @param localFlowEntry the local Flow Entry to update.
1016 * @param newFlowEntry the FlowEntry with the new state.
1017 * @return true if the local Flow Entry was updated, otherwise false.
1018 */
1019 private boolean updateFlowEntryAdd(FlowPath flowPath,
1020 FlowEntry localFlowEntry,
1021 FlowEntry newFlowEntry) {
1022 boolean updated = false;
1023
1024 if (localFlowEntry.flowEntryUserState() ==
1025 FlowEntryUserState.FE_USER_DELETE) {
1026 // Don't add-back a Flow Entry that is already deleted
1027 return false;
1028 }
1029
1030 if (! localFlowEntry.isValidFlowEntryId()) {
1031 // Update the Flow Entry ID
1032 FlowEntryId flowEntryId =
1033 new FlowEntryId(newFlowEntry.flowEntryId().value());
1034 localFlowEntry.setFlowEntryId(flowEntryId);
1035 updated = true;
1036 }
1037
1038 //
1039 // Update the local Flow Entry, and keep state to check
1040 // if the Flow Path has been installed.
1041 //
1042 if (localFlowEntry.flowEntryUserState() !=
1043 newFlowEntry.flowEntryUserState()) {
1044 localFlowEntry.setFlowEntryUserState(
1045 newFlowEntry.flowEntryUserState());
1046 updated = true;
1047 }
1048 if (localFlowEntry.flowEntrySwitchState() !=
1049 newFlowEntry.flowEntrySwitchState()) {
1050 localFlowEntry.setFlowEntrySwitchState(
1051 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001052 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001053 updated = true;
1054 }
1055
1056 return updated;
1057 }
1058
1059 /**
1060 * Find a Flow Entry that should be updated because of an external
1061 * ENTRY_REMOVE event.
1062 *
1063 * @param flowPath the FlowPath for the Flow Entry to update.
1064 * @param newFlowEntry the FlowEntry with the new state.
1065 * @return the Flow Entry that should be updated if found, otherwise null.
1066 */
1067 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1068 FlowEntry newFlowEntry) {
1069 //
1070 // Iterate over all Flow Entries and find a match based on
1071 // the Flow Entry ID.
1072 //
1073 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1074 if (! localFlowEntry.isValidFlowEntryId())
1075 continue;
1076 if (localFlowEntry.flowEntryId().value() !=
1077 newFlowEntry.flowEntryId().value()) {
1078 continue;
1079 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001080 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001081 }
1082
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001083 return null; // Entry not found
1084 }
1085
1086 /**
1087 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1088 *
1089 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001090 * @param localFlowEntry the local Flow Entry to update.
1091 * @param newFlowEntry the FlowEntry with the new state.
1092 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001093 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001094 private boolean updateFlowEntryRemove(FlowPath flowPath,
1095 FlowEntry localFlowEntry,
1096 FlowEntry newFlowEntry) {
1097 boolean updated = false;
1098
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001099 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001100 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001101 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001102 if (localFlowEntry.flowEntryUserState() !=
1103 newFlowEntry.flowEntryUserState()) {
1104 localFlowEntry.setFlowEntryUserState(
1105 newFlowEntry.flowEntryUserState());
1106 updated = true;
1107 }
1108 if (localFlowEntry.flowEntrySwitchState() !=
1109 newFlowEntry.flowEntrySwitchState()) {
1110 localFlowEntry.setFlowEntrySwitchState(
1111 newFlowEntry.flowEntrySwitchState());
1112 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001113 }
1114
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001115 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001116 }
1117
1118 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001119 * Recompute a Flow Path.
1120 *
1121 * @param flowPath the Flow Path to recompute.
1122 * @return true if the recomputed Flow Path has changed, otherwise false.
1123 */
1124 private boolean recomputeFlowPath(FlowPath flowPath) {
1125 boolean hasChanged = false;
1126
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001127 if (enableOnrc2014MeasurementsFlows) {
1128 // Cleanup the deleted Flow Entries from the earlier iteration
1129 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001130
1131 //
1132 // TODO: Fake it that the Flow Entries have been already pushed
1133 // into the switches, so we don't push them again.
1134 //
1135 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1136 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1137 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001138 }
1139
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001140 //
1141 // Test whether the Flow Path needs to be recomputed
1142 //
1143 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001144 case FP_TYPE_UNKNOWN:
1145 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001146 case FP_TYPE_SHORTEST_PATH:
1147 break;
1148 case FP_TYPE_EXPLICIT_PATH:
1149 return false; // An explicit path never changes
1150 }
1151
1152 DataPath oldDataPath = flowPath.dataPath();
1153
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001154 // Compute the new path
Naoki Shiota9f6fc212014-01-09 21:38:08 -08001155 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001156 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001157
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001158 if (newDataPath == null) {
1159 // We need the DataPath to compare the paths
1160 newDataPath = new DataPath();
1161 }
1162 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1163
1164 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001165 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001166 //
1167 if (oldDataPath.flowEntries().size() !=
1168 newDataPath.flowEntries().size()) {
1169 hasChanged = true;
1170 } else {
1171 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1172 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1173 while (oldIter.hasNext() && newIter.hasNext()) {
1174 FlowEntry oldFlowEntry = oldIter.next();
1175 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001176 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1177 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001178 hasChanged = true;
1179 break;
1180 }
1181 }
1182 }
1183 if (! hasChanged)
1184 return hasChanged;
1185
1186 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001187 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001188 // - If a Flow Entry for a switch is in the old data path, but not
1189 // in the new data path, then mark it for deletion.
1190 // - If a Flow Entry for a switch is in the new data path, but not
1191 // in the old data path, then mark it for addition.
1192 // - If a Flow Entry for a switch is in both the old and the new
1193 // data path, but it has changed, e.g., the incoming and/or outgoing
1194 // port(s), then mark the old Flow Entry for deletion, and mark
1195 // the new Flow Entry for addition.
1196 // - If a Flow Entry for a switch is in both the old and the new
1197 // data path, and it hasn't changed, then just keep it.
1198 //
1199 // NOTE: We use the Switch DPID of each entry to match the entries
1200 //
1201 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1202 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1203 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1204 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1205
1206 // Prepare maps with the Flow Entries, so they are fast to lookup
1207 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1208 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1209 for (FlowEntry flowEntry : newDataPath.flowEntries())
1210 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1211
1212 //
1213 // Find the old Flow Entries that should be deleted
1214 //
1215 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1216 FlowEntry newFlowEntry =
1217 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1218 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001219 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001220 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1221 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1222 deletedFlowEntries.add(oldFlowEntry);
1223 }
1224 }
1225
1226 //
1227 // Find the new Flow Entries that should be added or updated
1228 //
1229 int idx = 0;
1230 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1231 FlowEntry oldFlowEntry =
1232 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1233
1234 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001235 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1236 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001237 //
1238 // Both Flow Entries are same
1239 //
1240 finalFlowEntries.add(oldFlowEntry);
1241 idx++;
1242 continue;
1243 }
1244
1245 if (oldFlowEntry != null) {
1246 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001247 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001248 //
1249 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1250 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1251 deletedFlowEntries.add(oldFlowEntry);
1252 }
1253
1254 //
1255 // Add the new Flow Entry
1256 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001257 //
1258 // NOTE: Assign only the Flow ID.
1259 // The Flow Entry ID is assigned later only for the Flow Entries
1260 // this instance is responsible for.
1261 //
1262 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001263
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001264 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001265 // Copy the Flow timeouts
1266 //
1267 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1268 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1269
1270 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001271 // Allocate the FlowEntryMatch by copying the default one
1272 // from the FlowPath (if set).
1273 //
1274 FlowEntryMatch flowEntryMatch = null;
1275 if (flowPath.flowEntryMatch() != null)
1276 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1277 else
1278 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001279 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001280
1281 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001282 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1283
1284 //
1285 // Set the actions:
1286 // If the first Flow Entry, copy the Flow Path actions to it.
1287 //
1288 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1289 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1290 FlowEntryActions flowActions =
1291 new FlowEntryActions(flowPath.flowEntryActions());
1292 for (FlowEntryAction action : flowActions.actions())
1293 flowEntryActions.addAction(action);
1294 }
1295 idx++;
1296
1297 //
1298 // Add the outgoing port output action
1299 //
1300 FlowEntryAction flowEntryAction = new FlowEntryAction();
1301 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1302 flowEntryActions.addAction(flowEntryAction);
1303
1304 //
1305 // Set the state of the new Flow Entry
1306 //
1307 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1308 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1309 finalFlowEntries.add(newFlowEntry);
1310 }
1311
1312 //
1313 // Replace the old Flow Entries with the new Flow Entries.
1314 // Note that the Flow Entries that will be deleted are added at
1315 // the end.
1316 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001317 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001318 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1319
1320 return hasChanged;
1321 }
1322
1323 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001324 * Receive a notification that a Flow is added.
1325 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001326 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001327 */
1328 @Override
1329 public void notificationRecvFlowAdded(FlowPath flowPath) {
1330 EventEntry<FlowPath> eventEntry =
1331 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1332 networkEvents.add(eventEntry);
1333 }
1334
1335 /**
1336 * Receive a notification that a Flow is removed.
1337 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001338 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001339 */
1340 @Override
1341 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1342 EventEntry<FlowPath> eventEntry =
1343 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1344 networkEvents.add(eventEntry);
1345 }
1346
1347 /**
1348 * Receive a notification that a Flow is updated.
1349 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001350 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001351 */
1352 @Override
1353 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1354 // NOTE: The ADD and UPDATE events are processed in same way
1355 EventEntry<FlowPath> eventEntry =
1356 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1357 networkEvents.add(eventEntry);
1358 }
1359
1360 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001361 * Receive a notification that a FlowEntry is added.
1362 *
1363 * @param flowEntry the FlowEntry that is added.
1364 */
1365 @Override
1366 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001367 if (enableOnrc2014MeasurementsFlows) {
1368 Collection entries = new ArrayList();
1369 entries.add(flowEntry);
1370 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1371 return;
1372 }
1373
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001374 EventEntry<FlowEntry> eventEntry =
1375 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1376 networkEvents.add(eventEntry);
1377 }
1378
1379 /**
1380 * Receive a notification that a FlowEntry is removed.
1381 *
1382 * @param flowEntry the FlowEntry that is removed.
1383 */
1384 @Override
1385 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001386 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001387 //
1388 // NOTE: Must update the state to DELETE, because
1389 // the notification contains the original state.
1390 //
1391 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1392
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001393 Collection entries = new ArrayList();
1394 entries.add(flowEntry);
1395 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1396 return;
1397 }
1398
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001399 EventEntry<FlowEntry> eventEntry =
1400 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1401 networkEvents.add(eventEntry);
1402 }
1403
1404 /**
1405 * Receive a notification that a FlowEntry is updated.
1406 *
1407 * @param flowEntry the FlowEntry that is updated.
1408 */
1409 @Override
1410 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001411 if (enableOnrc2014MeasurementsFlows) {
1412 Collection entries = new ArrayList();
1413 entries.add(flowEntry);
1414 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1415 return;
1416 }
1417
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001418 // NOTE: The ADD and UPDATE events are processed in same way
1419 EventEntry<FlowEntry> eventEntry =
1420 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1421 networkEvents.add(eventEntry);
1422 }
1423
1424 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001425 * Receive a notification that a FlowId is added.
1426 *
1427 * @param flowId the FlowId that is added.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001428 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001429 */
1430 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001431 public void notificationRecvFlowIdAdded(FlowId flowId, Dpid dpid) {
1432 Pair flowIdPair = new Pair(flowId, dpid);
1433
1434 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1435 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001436 networkEvents.add(eventEntry);
1437 }
1438
1439 /**
1440 * Receive a notification that a FlowId is removed.
1441 *
1442 * @param flowId the FlowId that is removed.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001443 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001444 */
1445 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001446 public void notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1447 Pair flowIdPair = new Pair(flowId, dpid);
1448
1449 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1450 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001451 networkEvents.add(eventEntry);
1452 }
1453
1454 /**
1455 * Receive a notification that a FlowId is updated.
1456 *
1457 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001458 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001459 */
1460 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001461 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1462 Pair flowIdPair = new Pair(flowId, dpid);
1463
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001464 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001465 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1466 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001467 networkEvents.add(eventEntry);
1468 }
1469
1470 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001471 * Receive a notification that a FlowEntryId is added.
1472 *
1473 * @param flowEntryId the FlowEntryId that is added.
1474 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1475 */
1476 @Override
1477 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1478 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001479 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1480
1481 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1482 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001483 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001484 }
1485
1486 /**
1487 * Receive a notification that a FlowEntryId is removed.
1488 *
1489 * @param flowEntryId the FlowEntryId that is removed.
1490 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1491 */
1492 @Override
1493 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1494 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001495 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1496
1497 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1498 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001499 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001500 }
1501
1502 /**
1503 * Receive a notification that a FlowEntryId is updated.
1504 *
1505 * @param flowEntryId the FlowEntryId that is updated.
1506 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1507 */
1508 @Override
1509 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1510 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001511 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1512
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001513 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001514 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1515 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001516 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001517 }
1518
1519 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001520 * Receive a notification that a Topology Element is added.
1521 *
1522 * @param topologyElement the Topology Element that is added.
1523 */
1524 @Override
1525 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1526 EventEntry<TopologyElement> eventEntry =
1527 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1528 networkEvents.add(eventEntry);
1529 }
1530
1531 /**
1532 * Receive a notification that a Topology Element is removed.
1533 *
1534 * @param topologyElement the Topology Element that is removed.
1535 */
1536 @Override
1537 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1538 EventEntry<TopologyElement> eventEntry =
1539 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1540 networkEvents.add(eventEntry);
1541 }
1542
1543 /**
1544 * Receive a notification that a Topology Element is updated.
1545 *
1546 * @param topologyElement the Topology Element that is updated.
1547 */
1548 @Override
1549 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1550 // NOTE: The ADD and UPDATE events are processed in same way
1551 EventEntry<TopologyElement> eventEntry =
1552 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1553 networkEvents.add(eventEntry);
1554 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001555
1556 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001557 * Receive a notification that a switch is added to this instance.
1558 *
1559 * @param sw the switch that is added.
1560 */
1561 @Override
1562 public void addedSwitch(IOFSwitch sw) {
1563 Dpid dpid = new Dpid(sw.getId());
1564 EventEntry<Dpid> eventEntry =
1565 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1566 networkEvents.add(eventEntry);
1567 }
1568
1569 /**
1570 * Receive a notification that a switch is removed from this instance.
1571 *
1572 * @param sw the switch that is removed.
1573 */
1574 @Override
1575 public void removedSwitch(IOFSwitch sw) {
1576 Dpid dpid = new Dpid(sw.getId());
1577 EventEntry<Dpid> eventEntry =
1578 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1579 networkEvents.add(eventEntry);
1580 }
1581
1582 /**
1583 * Receive a notification that the ports on a switch have changed.
1584 */
1585 @Override
1586 public void switchPortChanged(Long switchId) {
1587 // Nothing to do
1588 }
1589
1590 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001591 * Get a sorted copy of all Flow Paths.
1592 *
1593 * @return a sorted copy of all Flow Paths.
1594 */
1595 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1596 SortedMap<Long, FlowPath> sortedFlowPaths =
1597 new TreeMap<Long, FlowPath>();
1598
1599 //
1600 // TODO: For now we use serialization/deserialization to create
1601 // a copy of each Flow Path. In the future, we should use proper
1602 // copy constructors.
1603 //
1604 Kryo kryo = kryoFactory.newKryo();
1605 synchronized (allFlowPaths) {
1606 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1607 FlowPath origFlowPath = entry.getValue();
1608 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1609 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1610 }
1611 }
1612 kryoFactory.deleteKryo(kryo);
1613
1614 return sortedFlowPaths;
1615 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001616}