blob: b414bc64216cb595bbcc3af220b955c45b5a3577 [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);
331 ParallelFlowDatabaseOperation.deleteFlow(dbHandler,
332 flowPath.flowId(),
333 datagridService);
334 continue;
335 }
336
337 log.debug("Pushing Flow Path To Database: {}", flowPath);
338 //
339 // Write the Flow Path to the Network Map
340 //
341 ParallelFlowDatabaseOperation.addFlow(dbHandler, flowPath,
342 datagridService);
343 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800344
345 // Cleanup
346 topologyEvents.clear();
347 flowIdEvents.clear();
Pavlin Radoslavov2d6e5f12014-01-10 16:34:05 -0800348 switchDpidEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800349 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800350 // NOTE: Keep a cache with my Flow Paths
351 // allFlowPaths.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800352 shouldRecomputeFlowPaths.clear();
353 modifiedFlowPaths.clear();
354
355 return;
356 }
357
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700358 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800359 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700360 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700361 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700362
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800363 processFlowPathEvents();
364 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800365 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800366 processFlowEntryEvents();
367
368 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800369 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800370 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800371 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800372 }
373
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800374 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800375 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800376
377 // Assign missing Flow Entry IDs
378 assignFlowEntryId(modifiedFlowEntries);
379
380 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800381 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800382 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800383 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
384 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800385
386 //
387 // Remove Flow Entries that were deleted
388 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800389 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800390 flowPath.dataPath().removeDeletedFlowEntries();
391
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800392 //
393 // Check if Flow Paths have been installed into all switches,
394 // and generate the appropriate events.
395 //
396 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
397
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800398 // Cleanup
399 topologyEvents.clear();
400 flowPathEvents.clear();
401 flowEntryEvents.clear();
402 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800403 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800404 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800405 checkIfInstalledFlowPaths.clear();
406 }
407
408 /**
409 * Check if Flow Paths have been installed into all switches,
410 * and generate the appropriate events.
411 *
412 * @param flowPaths the flowPaths to process.
413 */
414 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
415 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
416
417 Kryo kryo = kryoFactory.newKryo();
418
419 for (FlowPath flowPath : flowPaths) {
420 boolean isInstalled = true;
421
422 //
423 // Check whether all Flow Entries have been installed
424 //
425 for (FlowEntry flowEntry : flowPath.flowEntries()) {
426 if (flowEntry.flowEntrySwitchState() !=
427 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
428 isInstalled = false;
429 break;
430 }
431 }
432
433 if (isInstalled) {
434 // Create a copy and add it to the list
435 FlowPath copyFlowPath = kryo.copy(flowPath);
436 installedFlowPaths.add(copyFlowPath);
437 }
438 }
439 kryoFactory.deleteKryo(kryo);
440
441 // Generate an event for the installed Flow Path.
442 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800443 }
444
445 /**
446 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800447 *
448 * @param modifiedFlowPaths the Flow Paths to process.
449 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800450 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800451 private Collection<FlowEntry> extractModifiedFlowEntries(
452 Collection<FlowPath> modifiedFlowPaths) {
453 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800454
455 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800456 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800457 for (FlowEntry flowEntry : flowPath.flowEntries()) {
458 if (flowEntry.flowEntrySwitchState() ==
459 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800460 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800461 }
462 }
463 }
464 return modifiedFlowEntries;
465 }
466
467 /**
468 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800469 *
470 * @param modifiedFlowEnries the collection of Flow Entries that need
471 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800472 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800473 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800474 if (modifiedFlowEntries.isEmpty())
475 return;
476
477 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
478
479 //
480 // Assign the Flow Entry ID only for Flow Entries for my switches
481 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800482 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800483 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
484 if (mySwitch == null)
485 continue;
486 if (! flowEntry.isValidFlowEntryId()) {
487 long id = flowManager.getNextFlowEntryId();
488 flowEntry.setFlowEntryId(new FlowEntryId(id));
489 }
490 }
491 }
492
493 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800494 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800495 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800496 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800497 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800498 private void fixFlowFromDatabase(FlowPath flowPath) {
499 //
500 // TODO: Bug workaround / fix :
501 // method FlowDatabaseOperation.extractFlowEntry() doesn't
502 // fetch the inPort and outPort, hence we assign them here.
503 //
504 // Assign the inPort and outPort for the Flow Entries
505 for (FlowEntry flowEntry : flowPath.flowEntries()) {
506 // Set the inPort
507 do {
508 if (flowEntry.inPort() != null)
509 break;
510 if (flowEntry.flowEntryMatch() == null)
511 break;
512 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
513 flowEntry.setInPort(inPort);
514 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800515
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800516 // Set the outPort
517 do {
518 if (flowEntry.outPort() != null)
519 break;
520 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
521 if (fa.actionOutput() != null) {
522 Port outPort = new Port(fa.actionOutput().port().value());
523 flowEntry.setOutPort(outPort);
524 break;
525 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800526 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800527 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800528 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800529 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800530
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800531 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800532 * Process the Switch Dpid events.
533 */
534 private void processSwitchDpidEvents() {
535 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
536 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
537
538 //
539 // Process all Switch Dpid events and update the appropriate state
540 //
541 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
542 Dpid dpid = eventEntry.eventData();
543
544 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
545
546 // Compute the final set of added and removed switches
547 switch (eventEntry.eventType()) {
548 case ENTRY_ADD:
549 addedSwitches.put(dpid.value(), dpid);
550 removedSwitches.remove(dpid.value());
551 break;
552 case ENTRY_REMOVE:
553 addedSwitches.remove(dpid.value());
554 removedSwitches.put(dpid.value(), dpid);
555 break;
556 }
557 }
558
559 //
560 // Remove the Flows from the local cache if the removed
561 // switch is the Source Switch.
562 //
563 // TODO: This search can be expensive for a large number of flows
564 // and should be optmized.
565 //
566 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
567 for (Dpid switchDpid : removedSwitches.values()) {
568 for (FlowPath flowPath : allFlowPaths.values()) {
569 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
570 if (srcDpid.value() == switchDpid.value())
571 deleteFlowIds.add(flowPath.flowId());
572 }
573 }
574 //
575 // Remove the Flows from the local cache
576 //
577 for (FlowId flowId : deleteFlowIds)
578 allFlowPaths.remove(flowId.value());
579
580 // Get the Flows for the added switches
581 Collection<FlowPath> flowPaths =
582 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
583 addedSwitches.values());
584 for (FlowPath flowPath : flowPaths) {
585 allFlowPaths.put(flowPath.flowId().value(), flowPath);
586 }
587 }
588
589 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800590 * Process the Flow ID events.
591 *
592 * @param mySwitches the collection of my switches.
593 */
594 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800595 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
596
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800597 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800598 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800599 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800600 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
601 Pair<FlowId, Dpid> pair = eventEntry.eventData();
602 FlowId flowId = pair.first;
603 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800604
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800605 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
606 flowId, dpid);
607
608 //
609 // Ignore Flows if the Source Switch is not controlled by this
610 // instance.
611 //
612 if (mySwitches.get(dpid.value()) == null)
613 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800614
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800615 switch (eventEntry.eventType()) {
616 case ENTRY_ADD: {
617 //
618 // Add a new Flow Path
619 //
620 if (allFlowPaths.get(flowId.value()) != null) {
621 //
622 // TODO: What to do if the Flow Path already exists?
623 // Fow now, we just re-add it.
624 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800625 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800626 shouldFetchMyFlowIds.add(flowId);
627
628 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800629 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800630
631 case ENTRY_REMOVE: {
632 //
633 // Remove an existing Flow Path.
634 //
635 // Find the Flow Path, and mark the Flow and its Flow Entries
636 // for deletion.
637 //
638 FlowPath existingFlowPath =
639 allFlowPaths.get(flowId.value());
640 if (existingFlowPath == null)
641 continue; // Nothing to do
642
643 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
644 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
645 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
646 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
647 }
648
649 // Remove the Flow Path from the internal state
650 Long key = existingFlowPath.flowId().value();
651 allFlowPaths.remove(key);
652 shouldRecomputeFlowPaths.remove(key);
653 modifiedFlowPaths.put(key, existingFlowPath);
654
655 break;
656 }
657 }
658 }
659
660 // Get my Flows
661 Collection<FlowPath> myFlows =
Pavlin Radoslavov6602b6a2014-01-10 16:43:29 -0800662 ParallelFlowDatabaseOperation.getFlows(dbHandler,
663 shouldFetchMyFlowIds);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800664
665 for (FlowPath flowPath : myFlows) {
666 fixFlowFromDatabase(flowPath);
667
668 switch (flowPath.flowPathType()) {
669 case FP_TYPE_SHORTEST_PATH:
670 //
671 // Reset the Data Path, in case it was set already, because
672 // we are going to recompute it anyway.
673 //
674 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800675 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
676 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800677 break;
678 case FP_TYPE_EXPLICIT_PATH:
679 //
680 // Mark all Flow Entries for installation in the switches.
681 //
682 for (FlowEntry flowEntry : flowPath.flowEntries()) {
683 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
684 }
685 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
686 break;
687 case FP_TYPE_UNKNOWN:
688 log.error("FlowPath event with unknown type");
689 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800690 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800691 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800692 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800693 }
694
695 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800696 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800697 *
698 * @param mySwitches the collection of my switches.
699 * @return a collection of modified Flow Entries this instance needs
700 * to push to its own switches.
701 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800702 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800703 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
704
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800705 //
706 // Process all Flow ID events and update the appropriate state
707 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800708 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
709 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
710 FlowEntryId flowEntryId = pair.first;
711 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800712
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800713 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
714 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800715
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800716 if (mySwitches.get(dpid.value()) == null)
717 continue;
718
719 // Fetch the Flow Entry
720 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
721 flowEntryId);
722 if (flowEntry == null) {
723 log.debug("Flow Entry ID {} : Flow Entry not found!",
724 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800725 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800726 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800727 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800728 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800729
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800730 return modifiedFlowEntries;
731 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800732
733 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800734 * Process the Flow Path events.
735 */
736 private void processFlowPathEvents() {
737 //
738 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700739 //
740 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
741 FlowPath flowPath = eventEntry.eventData();
742
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800743 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800744
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700745 switch (eventEntry.eventType()) {
746 case ENTRY_ADD: {
747 //
748 // Add a new Flow Path
749 //
750 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
751 //
752 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800753 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700754 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700755 }
756
757 switch (flowPath.flowPathType()) {
758 case FP_TYPE_SHORTEST_PATH:
759 //
760 // Reset the Data Path, in case it was set already, because
761 // we are going to recompute it anyway.
762 //
763 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800764 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
765 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700766 break;
767 case FP_TYPE_EXPLICIT_PATH:
768 //
769 // Mark all Flow Entries for installation in the switches.
770 //
771 for (FlowEntry flowEntry : flowPath.flowEntries()) {
772 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
773 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800774 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700775 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800776 case FP_TYPE_UNKNOWN:
777 log.error("FlowPath event with unknown type");
778 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700779 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800780 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700781
782 break;
783 }
784
785 case ENTRY_REMOVE: {
786 //
787 // Remove an existing Flow Path.
788 //
789 // Find the Flow Path, and mark the Flow and its Flow Entries
790 // for deletion.
791 //
792 FlowPath existingFlowPath =
793 allFlowPaths.get(flowPath.flowId().value());
794 if (existingFlowPath == null)
795 continue; // Nothing to do
796
797 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
798 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
799 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
800 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
801 }
802
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800803 // Remove the Flow Path from the internal state
804 Long key = existingFlowPath.flowId().value();
805 allFlowPaths.remove(key);
806 shouldRecomputeFlowPaths.remove(key);
807 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700808
809 break;
810 }
811 }
812 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800813 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700814
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800815 /**
816 * Process the Topology events.
817 */
818 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800819 boolean isTopologyModified = false;
820
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800821 if (enableOnrc2014MeasurementsTopology) {
822 if (topologyEvents.isEmpty())
823 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800824
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800825 // TODO: Code for debugging purpose only
826 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
827 TopologyElement topologyElement = eventEntry.eventData();
828 log.debug("Topology Event: {} {}", eventEntry.eventType(),
829 topologyElement.toString());
830 }
831
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800832 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800833 topology.readFromDatabase(dbHandler);
834 log.debug("[AFTER] {}", topology.toString());
835 shouldRecomputeFlowPaths.putAll(allFlowPaths);
836 return;
837 }
838
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700839 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800840 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700841 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800842 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
843 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800844
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800845 log.debug("Topology Event: {} {}", eventEntry.eventType(),
846 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800847
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800848 switch (eventEntry.eventType()) {
849 case ENTRY_ADD:
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800850 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800851 break;
852 case ENTRY_REMOVE:
Naoki Shiota9f6fc212014-01-09 21:38:08 -0800853 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800854 break;
855 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700856 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700857 if (isTopologyModified) {
858 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800859 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700860 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800861 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700862
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800863 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800864 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800865 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800866 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800867 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800868 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800869
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700870 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800871 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700872 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800873 if (! unmatchedFlowEntryAdd.isEmpty()) {
874 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
875 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800876 // log.debug("Processing Unmatched Flow Entry: {}",
877 // flowEntry.toString());
878
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800879 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800880 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800881 remainingUpdates.put(flowEntry.flowEntryId().value(),
882 flowEntry);
883 continue;
884 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800885 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
886 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800887 remainingUpdates.put(flowEntry.flowEntryId().value(),
888 flowEntry);
889 continue;
890 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800891 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
892 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
893 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700894 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800895 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700896 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800897 }
898
899 /**
900 * Process the Flow Entry events.
901 */
902 private void processFlowEntryEvents() {
903 FlowPath flowPath;
904 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700905
906 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800907 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700908 //
909 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
910 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800911
912 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800913 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800914
915 if ((! flowEntry.isValidFlowId()) ||
916 (! flowEntry.isValidFlowEntryId())) {
917 continue;
918 }
919
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700920 switch (eventEntry.eventType()) {
921 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800922 flowPath = allFlowPaths.get(flowEntry.flowId().value());
923 if (flowPath == null) {
924 // Flow Path not found: keep the entry for later matching
925 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
926 flowEntry);
927 break;
928 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800929 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
930 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800931 // Flow Entry not found: keep the entry for later matching
932 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
933 flowEntry);
934 break;
935 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800936 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
937 // Add the updated Flow Path to the list of updated paths
938 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
939 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700940 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800941
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700942 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800943 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
944 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800945 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800946 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800947
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800948 flowPath = allFlowPaths.get(flowEntry.flowId().value());
949 if (flowPath == null) {
950 // Flow Path not found: ignore the update
951 break;
952 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800953 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
954 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800955 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800956 break;
957 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800958 if (updateFlowEntryRemove(flowPath, localFlowEntry,
959 flowEntry)) {
960 // Add the updated Flow Path to the list of updated paths
961 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
962 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700963 break;
964 }
965 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700966 }
967
968 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800969 * Find a Flow Entry that should be updated because of an external
970 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700971 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800972 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800973 * @param newFlowEntry the FlowEntry with the new state.
974 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700975 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800976 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
977 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700978 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800979 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700980 //
981 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800982 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800983 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700984 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800985 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700986
987 //
988 // Local Flow Entry match found
989 //
990 if (localFlowEntry.isValidFlowEntryId()) {
991 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800992 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700993 //
994 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800995 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700996 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800997 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700998 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700999 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001000 return localFlowEntry;
1001 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001002
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001003 return null; // Entry not found
1004 }
1005
1006 /**
1007 * Update a Flow Entry because of an external ENTRY_ADD event.
1008 *
1009 * @param flowPath the FlowPath for the Flow Entry to update.
1010 * @param localFlowEntry the local Flow Entry to update.
1011 * @param newFlowEntry the FlowEntry with the new state.
1012 * @return true if the local Flow Entry was updated, otherwise false.
1013 */
1014 private boolean updateFlowEntryAdd(FlowPath flowPath,
1015 FlowEntry localFlowEntry,
1016 FlowEntry newFlowEntry) {
1017 boolean updated = false;
1018
1019 if (localFlowEntry.flowEntryUserState() ==
1020 FlowEntryUserState.FE_USER_DELETE) {
1021 // Don't add-back a Flow Entry that is already deleted
1022 return false;
1023 }
1024
1025 if (! localFlowEntry.isValidFlowEntryId()) {
1026 // Update the Flow Entry ID
1027 FlowEntryId flowEntryId =
1028 new FlowEntryId(newFlowEntry.flowEntryId().value());
1029 localFlowEntry.setFlowEntryId(flowEntryId);
1030 updated = true;
1031 }
1032
1033 //
1034 // Update the local Flow Entry, and keep state to check
1035 // if the Flow Path has been installed.
1036 //
1037 if (localFlowEntry.flowEntryUserState() !=
1038 newFlowEntry.flowEntryUserState()) {
1039 localFlowEntry.setFlowEntryUserState(
1040 newFlowEntry.flowEntryUserState());
1041 updated = true;
1042 }
1043 if (localFlowEntry.flowEntrySwitchState() !=
1044 newFlowEntry.flowEntrySwitchState()) {
1045 localFlowEntry.setFlowEntrySwitchState(
1046 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001047 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001048 updated = true;
1049 }
1050
1051 return updated;
1052 }
1053
1054 /**
1055 * Find a Flow Entry that should be updated because of an external
1056 * ENTRY_REMOVE event.
1057 *
1058 * @param flowPath the FlowPath for the Flow Entry to update.
1059 * @param newFlowEntry the FlowEntry with the new state.
1060 * @return the Flow Entry that should be updated if found, otherwise null.
1061 */
1062 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1063 FlowEntry newFlowEntry) {
1064 //
1065 // Iterate over all Flow Entries and find a match based on
1066 // the Flow Entry ID.
1067 //
1068 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1069 if (! localFlowEntry.isValidFlowEntryId())
1070 continue;
1071 if (localFlowEntry.flowEntryId().value() !=
1072 newFlowEntry.flowEntryId().value()) {
1073 continue;
1074 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001075 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001076 }
1077
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001078 return null; // Entry not found
1079 }
1080
1081 /**
1082 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1083 *
1084 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001085 * @param localFlowEntry the local Flow Entry to update.
1086 * @param newFlowEntry the FlowEntry with the new state.
1087 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001088 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001089 private boolean updateFlowEntryRemove(FlowPath flowPath,
1090 FlowEntry localFlowEntry,
1091 FlowEntry newFlowEntry) {
1092 boolean updated = false;
1093
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001094 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001095 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001096 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001097 if (localFlowEntry.flowEntryUserState() !=
1098 newFlowEntry.flowEntryUserState()) {
1099 localFlowEntry.setFlowEntryUserState(
1100 newFlowEntry.flowEntryUserState());
1101 updated = true;
1102 }
1103 if (localFlowEntry.flowEntrySwitchState() !=
1104 newFlowEntry.flowEntrySwitchState()) {
1105 localFlowEntry.setFlowEntrySwitchState(
1106 newFlowEntry.flowEntrySwitchState());
1107 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001108 }
1109
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001110 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001111 }
1112
1113 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001114 * Recompute a Flow Path.
1115 *
1116 * @param flowPath the Flow Path to recompute.
1117 * @return true if the recomputed Flow Path has changed, otherwise false.
1118 */
1119 private boolean recomputeFlowPath(FlowPath flowPath) {
1120 boolean hasChanged = false;
1121
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001122 if (enableOnrc2014MeasurementsFlows) {
1123 // Cleanup the deleted Flow Entries from the earlier iteration
1124 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001125
1126 //
1127 // TODO: Fake it that the Flow Entries have been already pushed
1128 // into the switches, so we don't push them again.
1129 //
1130 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1131 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1132 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001133 }
1134
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001135 //
1136 // Test whether the Flow Path needs to be recomputed
1137 //
1138 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001139 case FP_TYPE_UNKNOWN:
1140 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001141 case FP_TYPE_SHORTEST_PATH:
1142 break;
1143 case FP_TYPE_EXPLICIT_PATH:
1144 return false; // An explicit path never changes
1145 }
1146
1147 DataPath oldDataPath = flowPath.dataPath();
1148
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001149 // Compute the new path
Naoki Shiota9f6fc212014-01-09 21:38:08 -08001150 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001151 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001152
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001153 if (newDataPath == null) {
1154 // We need the DataPath to compare the paths
1155 newDataPath = new DataPath();
1156 }
1157 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1158
1159 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001160 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001161 //
1162 if (oldDataPath.flowEntries().size() !=
1163 newDataPath.flowEntries().size()) {
1164 hasChanged = true;
1165 } else {
1166 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1167 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1168 while (oldIter.hasNext() && newIter.hasNext()) {
1169 FlowEntry oldFlowEntry = oldIter.next();
1170 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001171 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1172 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001173 hasChanged = true;
1174 break;
1175 }
1176 }
1177 }
1178 if (! hasChanged)
1179 return hasChanged;
1180
1181 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001182 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001183 // - If a Flow Entry for a switch is in the old data path, but not
1184 // in the new data path, then mark it for deletion.
1185 // - If a Flow Entry for a switch is in the new data path, but not
1186 // in the old data path, then mark it for addition.
1187 // - If a Flow Entry for a switch is in both the old and the new
1188 // data path, but it has changed, e.g., the incoming and/or outgoing
1189 // port(s), then mark the old Flow Entry for deletion, and mark
1190 // the new Flow Entry for addition.
1191 // - If a Flow Entry for a switch is in both the old and the new
1192 // data path, and it hasn't changed, then just keep it.
1193 //
1194 // NOTE: We use the Switch DPID of each entry to match the entries
1195 //
1196 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1197 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1198 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1199 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1200
1201 // Prepare maps with the Flow Entries, so they are fast to lookup
1202 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1203 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1204 for (FlowEntry flowEntry : newDataPath.flowEntries())
1205 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1206
1207 //
1208 // Find the old Flow Entries that should be deleted
1209 //
1210 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1211 FlowEntry newFlowEntry =
1212 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1213 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001214 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001215 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1216 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1217 deletedFlowEntries.add(oldFlowEntry);
1218 }
1219 }
1220
1221 //
1222 // Find the new Flow Entries that should be added or updated
1223 //
1224 int idx = 0;
1225 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1226 FlowEntry oldFlowEntry =
1227 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1228
1229 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001230 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1231 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001232 //
1233 // Both Flow Entries are same
1234 //
1235 finalFlowEntries.add(oldFlowEntry);
1236 idx++;
1237 continue;
1238 }
1239
1240 if (oldFlowEntry != null) {
1241 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001242 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001243 //
1244 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1245 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1246 deletedFlowEntries.add(oldFlowEntry);
1247 }
1248
1249 //
1250 // Add the new Flow Entry
1251 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001252 //
1253 // NOTE: Assign only the Flow ID.
1254 // The Flow Entry ID is assigned later only for the Flow Entries
1255 // this instance is responsible for.
1256 //
1257 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001258
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001259 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001260 // Copy the Flow timeouts
1261 //
1262 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1263 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1264
1265 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001266 // Allocate the FlowEntryMatch by copying the default one
1267 // from the FlowPath (if set).
1268 //
1269 FlowEntryMatch flowEntryMatch = null;
1270 if (flowPath.flowEntryMatch() != null)
1271 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1272 else
1273 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001274 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001275
1276 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001277 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1278
1279 //
1280 // Set the actions:
1281 // If the first Flow Entry, copy the Flow Path actions to it.
1282 //
1283 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1284 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1285 FlowEntryActions flowActions =
1286 new FlowEntryActions(flowPath.flowEntryActions());
1287 for (FlowEntryAction action : flowActions.actions())
1288 flowEntryActions.addAction(action);
1289 }
1290 idx++;
1291
1292 //
1293 // Add the outgoing port output action
1294 //
1295 FlowEntryAction flowEntryAction = new FlowEntryAction();
1296 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1297 flowEntryActions.addAction(flowEntryAction);
1298
1299 //
1300 // Set the state of the new Flow Entry
1301 //
1302 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1303 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1304 finalFlowEntries.add(newFlowEntry);
1305 }
1306
1307 //
1308 // Replace the old Flow Entries with the new Flow Entries.
1309 // Note that the Flow Entries that will be deleted are added at
1310 // the end.
1311 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001312 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001313 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1314
1315 return hasChanged;
1316 }
1317
1318 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001319 * Receive a notification that a Flow is added.
1320 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001321 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001322 */
1323 @Override
1324 public void notificationRecvFlowAdded(FlowPath flowPath) {
1325 EventEntry<FlowPath> eventEntry =
1326 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1327 networkEvents.add(eventEntry);
1328 }
1329
1330 /**
1331 * Receive a notification that a Flow is removed.
1332 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001333 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001334 */
1335 @Override
1336 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1337 EventEntry<FlowPath> eventEntry =
1338 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1339 networkEvents.add(eventEntry);
1340 }
1341
1342 /**
1343 * Receive a notification that a Flow is updated.
1344 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001345 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001346 */
1347 @Override
1348 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1349 // NOTE: The ADD and UPDATE events are processed in same way
1350 EventEntry<FlowPath> eventEntry =
1351 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1352 networkEvents.add(eventEntry);
1353 }
1354
1355 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001356 * Receive a notification that a FlowEntry is added.
1357 *
1358 * @param flowEntry the FlowEntry that is added.
1359 */
1360 @Override
1361 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001362 if (enableOnrc2014MeasurementsFlows) {
1363 Collection entries = new ArrayList();
1364 entries.add(flowEntry);
1365 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1366 return;
1367 }
1368
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001369 EventEntry<FlowEntry> eventEntry =
1370 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1371 networkEvents.add(eventEntry);
1372 }
1373
1374 /**
1375 * Receive a notification that a FlowEntry is removed.
1376 *
1377 * @param flowEntry the FlowEntry that is removed.
1378 */
1379 @Override
1380 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001381 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001382 //
1383 // NOTE: Must update the state to DELETE, because
1384 // the notification contains the original state.
1385 //
1386 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1387
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001388 Collection entries = new ArrayList();
1389 entries.add(flowEntry);
1390 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1391 return;
1392 }
1393
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001394 EventEntry<FlowEntry> eventEntry =
1395 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1396 networkEvents.add(eventEntry);
1397 }
1398
1399 /**
1400 * Receive a notification that a FlowEntry is updated.
1401 *
1402 * @param flowEntry the FlowEntry that is updated.
1403 */
1404 @Override
1405 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001406 if (enableOnrc2014MeasurementsFlows) {
1407 Collection entries = new ArrayList();
1408 entries.add(flowEntry);
1409 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1410 return;
1411 }
1412
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001413 // NOTE: The ADD and UPDATE events are processed in same way
1414 EventEntry<FlowEntry> eventEntry =
1415 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1416 networkEvents.add(eventEntry);
1417 }
1418
1419 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001420 * Receive a notification that a FlowId is added.
1421 *
1422 * @param flowId the FlowId that is added.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001423 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001424 */
1425 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001426 public void notificationRecvFlowIdAdded(FlowId flowId, Dpid dpid) {
1427 Pair flowIdPair = new Pair(flowId, dpid);
1428
1429 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1430 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001431 networkEvents.add(eventEntry);
1432 }
1433
1434 /**
1435 * Receive a notification that a FlowId is removed.
1436 *
1437 * @param flowId the FlowId that is removed.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001438 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001439 */
1440 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001441 public void notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1442 Pair flowIdPair = new Pair(flowId, dpid);
1443
1444 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1445 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001446 networkEvents.add(eventEntry);
1447 }
1448
1449 /**
1450 * Receive a notification that a FlowId is updated.
1451 *
1452 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001453 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001454 */
1455 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001456 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1457 Pair flowIdPair = new Pair(flowId, dpid);
1458
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001459 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001460 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1461 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001462 networkEvents.add(eventEntry);
1463 }
1464
1465 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001466 * Receive a notification that a FlowEntryId is added.
1467 *
1468 * @param flowEntryId the FlowEntryId that is added.
1469 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1470 */
1471 @Override
1472 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1473 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001474 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1475
1476 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1477 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001478 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001479 }
1480
1481 /**
1482 * Receive a notification that a FlowEntryId is removed.
1483 *
1484 * @param flowEntryId the FlowEntryId that is removed.
1485 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1486 */
1487 @Override
1488 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1489 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001490 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1491
1492 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1493 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001494 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001495 }
1496
1497 /**
1498 * Receive a notification that a FlowEntryId is updated.
1499 *
1500 * @param flowEntryId the FlowEntryId that is updated.
1501 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1502 */
1503 @Override
1504 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1505 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001506 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1507
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001508 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001509 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1510 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001511 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001512 }
1513
1514 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001515 * Receive a notification that a Topology Element is added.
1516 *
1517 * @param topologyElement the Topology Element that is added.
1518 */
1519 @Override
1520 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1521 EventEntry<TopologyElement> eventEntry =
1522 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1523 networkEvents.add(eventEntry);
1524 }
1525
1526 /**
1527 * Receive a notification that a Topology Element is removed.
1528 *
1529 * @param topologyElement the Topology Element that is removed.
1530 */
1531 @Override
1532 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1533 EventEntry<TopologyElement> eventEntry =
1534 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1535 networkEvents.add(eventEntry);
1536 }
1537
1538 /**
1539 * Receive a notification that a Topology Element is updated.
1540 *
1541 * @param topologyElement the Topology Element that is updated.
1542 */
1543 @Override
1544 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1545 // NOTE: The ADD and UPDATE events are processed in same way
1546 EventEntry<TopologyElement> eventEntry =
1547 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1548 networkEvents.add(eventEntry);
1549 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001550
1551 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001552 * Receive a notification that a switch is added to this instance.
1553 *
1554 * @param sw the switch that is added.
1555 */
1556 @Override
1557 public void addedSwitch(IOFSwitch sw) {
1558 Dpid dpid = new Dpid(sw.getId());
1559 EventEntry<Dpid> eventEntry =
1560 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1561 networkEvents.add(eventEntry);
1562 }
1563
1564 /**
1565 * Receive a notification that a switch is removed from this instance.
1566 *
1567 * @param sw the switch that is removed.
1568 */
1569 @Override
1570 public void removedSwitch(IOFSwitch sw) {
1571 Dpid dpid = new Dpid(sw.getId());
1572 EventEntry<Dpid> eventEntry =
1573 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1574 networkEvents.add(eventEntry);
1575 }
1576
1577 /**
1578 * Receive a notification that the ports on a switch have changed.
1579 */
1580 @Override
1581 public void switchPortChanged(Long switchId) {
1582 // Nothing to do
1583 }
1584
1585 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001586 * Get a sorted copy of all Flow Paths.
1587 *
1588 * @return a sorted copy of all Flow Paths.
1589 */
1590 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1591 SortedMap<Long, FlowPath> sortedFlowPaths =
1592 new TreeMap<Long, FlowPath>();
1593
1594 //
1595 // TODO: For now we use serialization/deserialization to create
1596 // a copy of each Flow Path. In the future, we should use proper
1597 // copy constructors.
1598 //
1599 Kryo kryo = kryoFactory.newKryo();
1600 synchronized (allFlowPaths) {
1601 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1602 FlowPath origFlowPath = entry.getValue();
1603 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1604 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1605 }
1606 }
1607 kryoFactory.deleteKryo(kryo);
1608
1609 return sortedFlowPaths;
1610 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001611}