blob: feb80e132e33d70102156b0f1bd0be88302adfe8 [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 Radoslavov6b79f2b2013-10-26 21:31:10 -070010import java.util.concurrent.BlockingQueue;
11import java.util.concurrent.LinkedBlockingQueue;
12
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080013import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070014import net.onrc.onos.datagrid.IDatagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070015import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070016import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070017import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070018import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070019import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070020import net.onrc.onos.ofcontroller.util.FlowEntry;
21import net.onrc.onos.ofcontroller.util.FlowEntryAction;
22import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070023import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070024import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
25import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
26import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070027import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070028import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070029import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070030
31import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
34/**
Pavlin Radoslavov63117172013-11-07 02:18:37 -080035 * A class for storing a pair of Flow Path and a Flow Entry.
36 */
37class FlowPathEntryPair {
38 protected FlowPath flowPath;
39 protected FlowEntry flowEntry;
40
41 protected FlowPathEntryPair(FlowPath flowPath, FlowEntry flowEntry) {
42 this.flowPath = flowPath;
43 this.flowEntry = flowEntry;
44 }
45}
46
47/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070048 * Class for FlowPath Maintenance.
49 * This class listens for FlowEvents to:
50 * - Maintain a local cache of the Network Topology.
51 * - Detect FlowPaths impacted by Topology change.
52 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070053 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070054class FlowEventHandler extends Thread implements IFlowEventHandlerService {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070055 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070056 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070057
58 private FlowManager flowManager; // The Flow Manager to use
59 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070060 private Topology topology; // The network topology
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070061
62 // The queue with Flow Path and Topology Element updates
63 private BlockingQueue<EventEntry<?>> networkEvents =
64 new LinkedBlockingQueue<EventEntry<?>>();
65
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070066 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070067 private List<EventEntry<TopologyElement>> topologyEvents =
68 new LinkedList<EventEntry<TopologyElement>>();
69 private List<EventEntry<FlowPath>> flowPathEvents =
70 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070071 private List<EventEntry<FlowEntry>> flowEntryEvents =
72 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070073
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080074 // All internally computed Flow Paths
75 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
76
77 // The Flow Entries received as notifications with unmatched Flow Paths
78 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
79 new HashMap<Long, FlowEntry>();
80
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080081 //
82 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080083 // - The Flow Paths that should be recomputed
84 // - The Flow Paths with modified Flow Entries
85 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080086 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
87 new HashMap<Long, FlowPath>();
88 private Map<Long, FlowPath> modifiedFlowPaths =
89 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080090
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070091 /**
92 * Constructor for a given Flow Manager and Datagrid Service.
93 *
94 * @param flowManager the Flow Manager to use.
95 * @param datagridService the Datagrid Service to use.
96 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070097 FlowEventHandler(FlowManager flowManager,
98 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070099 this.flowManager = flowManager;
100 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700101 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700102 }
103
104 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800105 * Get the network topology.
106 *
107 * @return the network topology.
108 */
109 protected Topology getTopology() { return this.topology; }
110
111 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800112 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700113 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800114 private void startup() {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700115 //
116 // Obtain the initial Topology state
117 //
118 Collection<TopologyElement> topologyElements =
119 datagridService.getAllTopologyElements();
120 for (TopologyElement topologyElement : topologyElements) {
121 EventEntry<TopologyElement> eventEntry =
122 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
123 topologyEvents.add(eventEntry);
124 }
125 //
126 // Obtain the initial Flow Path state
127 //
128 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
129 for (FlowPath flowPath : flowPaths) {
130 EventEntry<FlowPath> eventEntry =
131 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
132 flowPathEvents.add(eventEntry);
133 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700134 //
135 // Obtain the initial FlowEntry state
136 //
137 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
138 for (FlowEntry flowEntry : flowEntries) {
139 EventEntry<FlowEntry> eventEntry =
140 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
141 flowEntryEvents.add(eventEntry);
142 }
143
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800144 // Process the initial events (if any)
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700145 processEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800146 }
147
148 /**
149 * Run the thread.
150 */
151 @Override
152 public void run() {
153 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700154
155 //
156 // The main loop
157 //
158 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
159 try {
160 while (true) {
161 EventEntry<?> eventEntry = networkEvents.take();
162 collection.add(eventEntry);
163 networkEvents.drainTo(collection);
164
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700165 //
166 // Demultiplex all events:
167 // - EventEntry<TopologyElement>
168 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700169 // - EventEntry<FlowEntry>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700170 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700171 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800172 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700173 if (event.eventData() instanceof TopologyElement) {
174 EventEntry<TopologyElement> topologyEventEntry =
175 (EventEntry<TopologyElement>)event;
176 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800177 continue;
178 }
179
180 // FlowPath event
181 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700182 EventEntry<FlowPath> flowPathEventEntry =
183 (EventEntry<FlowPath>)event;
184 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800185 continue;
186 }
187
188 // FlowEntry event
189 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700190 EventEntry<FlowEntry> flowEntryEventEntry =
191 (EventEntry<FlowEntry>)event;
192 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800193 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700194 }
195 }
196 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700197
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700198 // Process the events (if any)
199 processEvents();
200 }
201 } catch (Exception exception) {
202 log.debug("Exception processing Network Events: ", exception);
203 }
204 }
205
206 /**
207 * Process the events (if any)
208 */
209 private void processEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800210 List<FlowPathEntryPair> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700211
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700212 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
213 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700214 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700215 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700216
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800217 processFlowPathEvents();
218 processTopologyEvents();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800219 processFlowEntryEvents();
220
221 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800222 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800223 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800224 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800225 }
226
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800227 // Extract the modified Flow Entries
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800228 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths);
229
230 // Assign missing Flow Entry IDs
231 assignFlowEntryId(modifiedFlowEntries);
232
233 //
234 // Push the modified Flow Entries to switches, datagrid and database
235 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800236 flowManager.pushModifiedFlowEntriesToSwitches(modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800237 flowManager.pushModifiedFlowEntriesToDatagrid(modifiedFlowEntries);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800238 flowManager.pushModifiedFlowPathsToDatabase(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800239
240 //
241 // Remove Flow Entries that were deleted
242 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800243 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800244 flowPath.dataPath().removeDeletedFlowEntries();
245
246 // Cleanup
247 topologyEvents.clear();
248 flowPathEvents.clear();
249 flowEntryEvents.clear();
250 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800251 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800252 modifiedFlowPaths.clear();
253 }
254
255 /**
256 * Extract the modified Flow Entries.
257 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800258 private List<FlowPathEntryPair> extractModifiedFlowEntries(
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800259 Map<Long, FlowPath> modifiedFlowPaths) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800260 List<FlowPathEntryPair> modifiedFlowEntries =
261 new LinkedList<FlowPathEntryPair>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800262
263 // Extract only the modified Flow Entries
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800264 for (FlowPath flowPath : modifiedFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800265 for (FlowEntry flowEntry : flowPath.flowEntries()) {
266 if (flowEntry.flowEntrySwitchState() ==
267 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800268 FlowPathEntryPair flowPair =
269 new FlowPathEntryPair(flowPath, flowEntry);
270 modifiedFlowEntries.add(flowPair);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800271 }
272 }
273 }
274 return modifiedFlowEntries;
275 }
276
277 /**
278 * Assign the Flow Entry ID as needed.
279 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800280 private void assignFlowEntryId(List<FlowPathEntryPair> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800281 if (modifiedFlowEntries.isEmpty())
282 return;
283
284 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
285
286 //
287 // Assign the Flow Entry ID only for Flow Entries for my switches
288 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800289 for (FlowPathEntryPair flowPair : modifiedFlowEntries) {
290 FlowEntry flowEntry = flowPair.flowEntry;
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800291 // Update the Flow Entries only for my switches
292 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
293 if (mySwitch == null)
294 continue;
295 if (! flowEntry.isValidFlowEntryId()) {
296 long id = flowManager.getNextFlowEntryId();
297 flowEntry.setFlowEntryId(new FlowEntryId(id));
298 }
299 }
300 }
301
302 /**
303 * Process the Flow Path events.
304 */
305 private void processFlowPathEvents() {
306 //
307 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700308 //
309 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
310 FlowPath flowPath = eventEntry.eventData();
311
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800312 log.debug("Flow Event: {} {}", eventEntry.eventType(),
313 flowPath.toString());
314
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700315 switch (eventEntry.eventType()) {
316 case ENTRY_ADD: {
317 //
318 // Add a new Flow Path
319 //
320 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
321 //
322 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800323 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700324 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700325 }
326
327 switch (flowPath.flowPathType()) {
328 case FP_TYPE_SHORTEST_PATH:
329 //
330 // Reset the Data Path, in case it was set already, because
331 // we are going to recompute it anyway.
332 //
333 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800334 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
335 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700336 break;
337 case FP_TYPE_EXPLICIT_PATH:
338 //
339 // Mark all Flow Entries for installation in the switches.
340 //
341 for (FlowEntry flowEntry : flowPath.flowEntries()) {
342 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
343 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800344 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700345 break;
346 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800347 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700348
349 break;
350 }
351
352 case ENTRY_REMOVE: {
353 //
354 // Remove an existing Flow Path.
355 //
356 // Find the Flow Path, and mark the Flow and its Flow Entries
357 // for deletion.
358 //
359 FlowPath existingFlowPath =
360 allFlowPaths.get(flowPath.flowId().value());
361 if (existingFlowPath == null)
362 continue; // Nothing to do
363
364 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
365 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
366 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
367 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
368 }
369
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800370 // Remove the Flow Path from the internal state
371 Long key = existingFlowPath.flowId().value();
372 allFlowPaths.remove(key);
373 shouldRecomputeFlowPaths.remove(key);
374 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700375
376 break;
377 }
378 }
379 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800380 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700381
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800382 /**
383 * Process the Topology events.
384 */
385 private void processTopologyEvents() {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700386 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800387 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700388 //
389 boolean isTopologyModified = false;
390 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
391 TopologyElement topologyElement = eventEntry.eventData();
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800392
393 log.debug("Topology Event: {} {}", eventEntry.eventType(),
394 topologyElement.toString());
395
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700396 switch (eventEntry.eventType()) {
397 case ENTRY_ADD:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700398 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700399 break;
400 case ENTRY_REMOVE:
Yuta HIGUCHIb32f77f2013-10-30 15:36:32 -0700401 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700402 break;
403 }
404 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700405 if (isTopologyModified) {
406 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800407 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700408 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800409 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700410
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800411 /**
412 * Process the Flow Entry events.
413 */
414 private void processFlowEntryEvents() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800415 FlowPathEntryPair flowPair;
416 FlowPath flowPath;
417 FlowEntry updatedFlowEntry;
418
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700419 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800420 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700421 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800422 if (! unmatchedFlowEntryAdd.isEmpty()) {
423 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
424 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
425 flowPath = allFlowPaths.get(flowEntry.flowId().value());
426 if (flowPath == null)
427 continue;
428 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
429 if (updatedFlowEntry == null) {
430 remainingUpdates.put(flowEntry.flowEntryId().value(),
431 flowEntry);
432 continue;
433 }
434 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800435 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700436 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800437 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700438 }
439
440 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800441 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700442 //
443 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
444 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800445
446 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
447 flowEntry.toString());
448
449 if ((! flowEntry.isValidFlowId()) ||
450 (! flowEntry.isValidFlowEntryId())) {
451 continue;
452 }
453
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700454 switch (eventEntry.eventType()) {
455 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800456 flowPath = allFlowPaths.get(flowEntry.flowId().value());
457 if (flowPath == null) {
458 // Flow Path not found: keep the entry for later matching
459 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
460 flowEntry);
461 break;
462 }
463 updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
464 if (updatedFlowEntry == null) {
465 // Flow Entry not found: keep the entry for later matching
466 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
467 flowEntry);
468 break;
469 }
470 // Add the updated entry to the list of updated Flow Entries
471 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800472 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700473 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800474
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700475 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800476 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
477 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800478 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800479 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800480
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800481 flowPath = allFlowPaths.get(flowEntry.flowId().value());
482 if (flowPath == null) {
483 // Flow Path not found: ignore the update
484 break;
485 }
486 updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
487 if (updatedFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800488 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800489 break;
490 }
491 flowPair = new FlowPathEntryPair(flowPath, updatedFlowEntry);
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800492 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700493 break;
494 }
495 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700496 }
497
498 /**
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800499 * Update a Flow Entry because of an external ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700500 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800501 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700502 * @param flowEntry the FlowEntry with the new state.
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800503 * @return the updated Flow Entry if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700504 */
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800505 private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
506 FlowEntry flowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700507 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800508 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700509 //
510 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800511 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
512 flowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700513 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800514 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700515
516 //
517 // Local Flow Entry match found
518 //
519 if (localFlowEntry.isValidFlowEntryId()) {
520 if (localFlowEntry.flowEntryId().value() !=
521 flowEntry.flowEntryId().value()) {
522 //
523 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800524 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700525 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800526 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700527 }
528 } else {
529 // Update the Flow Entry ID
530 FlowEntryId flowEntryId =
531 new FlowEntryId(flowEntry.flowEntryId().value());
532 localFlowEntry.setFlowEntryId(flowEntryId);
533 }
534
535 //
536 // Update the local Flow Entry.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700537 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800538 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700539 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800540 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700541 }
542
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800543 return null; // Entry not found
544 }
545
546 /**
547 * Update a Flow Entry because of an external ENTRY_REMOVE event.
548 *
549 * @param flowPath the FlowPath for the Flow Entry to update.
550 * @param flowEntry the FlowEntry with the new state.
551 * @return the updated Flow Entry if found, otherwise null.
552 */
553 private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
554 FlowEntry flowEntry) {
555 //
556 // Iterate over all Flow Entries and find a match based on
557 // the Flow Entry ID.
558 //
559 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
560 if (! localFlowEntry.isValidFlowEntryId())
561 continue;
562 if (localFlowEntry.flowEntryId().value() !=
563 flowEntry.flowEntryId().value()) {
564 continue;
565 }
566 //
567 // Update the local Flow Entry.
568 //
569 localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
570 localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
571 return localFlowEntry;
572 }
573
574 return null; // Entry not found
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700575 }
576
577 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700578 * Recompute a Flow Path.
579 *
580 * @param flowPath the Flow Path to recompute.
581 * @return true if the recomputed Flow Path has changed, otherwise false.
582 */
583 private boolean recomputeFlowPath(FlowPath flowPath) {
584 boolean hasChanged = false;
585
586 //
587 // Test whether the Flow Path needs to be recomputed
588 //
589 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -0700590 case FP_TYPE_UNKNOWN:
591 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700592 case FP_TYPE_SHORTEST_PATH:
593 break;
594 case FP_TYPE_EXPLICIT_PATH:
595 return false; // An explicit path never changes
596 }
597
598 DataPath oldDataPath = flowPath.dataPath();
599
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700600 // Compute the new path
601 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
602 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700603 if (newDataPath == null) {
604 // We need the DataPath to compare the paths
605 newDataPath = new DataPath();
606 }
607 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
608
609 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700610 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700611 //
612 if (oldDataPath.flowEntries().size() !=
613 newDataPath.flowEntries().size()) {
614 hasChanged = true;
615 } else {
616 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
617 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
618 while (oldIter.hasNext() && newIter.hasNext()) {
619 FlowEntry oldFlowEntry = oldIter.next();
620 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700621 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
622 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700623 hasChanged = true;
624 break;
625 }
626 }
627 }
628 if (! hasChanged)
629 return hasChanged;
630
631 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700632 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700633 // - If a Flow Entry for a switch is in the old data path, but not
634 // in the new data path, then mark it for deletion.
635 // - If a Flow Entry for a switch is in the new data path, but not
636 // in the old data path, then mark it for addition.
637 // - If a Flow Entry for a switch is in both the old and the new
638 // data path, but it has changed, e.g., the incoming and/or outgoing
639 // port(s), then mark the old Flow Entry for deletion, and mark
640 // the new Flow Entry for addition.
641 // - If a Flow Entry for a switch is in both the old and the new
642 // data path, and it hasn't changed, then just keep it.
643 //
644 // NOTE: We use the Switch DPID of each entry to match the entries
645 //
646 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
647 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
648 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
649 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
650
651 // Prepare maps with the Flow Entries, so they are fast to lookup
652 for (FlowEntry flowEntry : oldDataPath.flowEntries())
653 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
654 for (FlowEntry flowEntry : newDataPath.flowEntries())
655 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
656
657 //
658 // Find the old Flow Entries that should be deleted
659 //
660 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
661 FlowEntry newFlowEntry =
662 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
663 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800664 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700665 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
666 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
667 deletedFlowEntries.add(oldFlowEntry);
668 }
669 }
670
671 //
672 // Find the new Flow Entries that should be added or updated
673 //
674 int idx = 0;
675 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
676 FlowEntry oldFlowEntry =
677 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
678
679 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700680 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
681 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700682 //
683 // Both Flow Entries are same
684 //
685 finalFlowEntries.add(oldFlowEntry);
686 idx++;
687 continue;
688 }
689
690 if (oldFlowEntry != null) {
691 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800692 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700693 //
694 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
695 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
696 deletedFlowEntries.add(oldFlowEntry);
697 }
698
699 //
700 // Add the new Flow Entry
701 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700702 //
703 // NOTE: Assign only the Flow ID.
704 // The Flow Entry ID is assigned later only for the Flow Entries
705 // this instance is responsible for.
706 //
707 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700708
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800709 //
710 // Allocate the FlowEntryMatch by copying the default one
711 // from the FlowPath (if set).
712 //
713 FlowEntryMatch flowEntryMatch = null;
714 if (flowPath.flowEntryMatch() != null)
715 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
716 else
717 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700718 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -0800719
720 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700721 flowEntryMatch.enableInPort(newFlowEntry.inPort());
722
723 //
724 // Set the actions:
725 // If the first Flow Entry, copy the Flow Path actions to it.
726 //
727 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
728 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
729 FlowEntryActions flowActions =
730 new FlowEntryActions(flowPath.flowEntryActions());
731 for (FlowEntryAction action : flowActions.actions())
732 flowEntryActions.addAction(action);
733 }
734 idx++;
735
736 //
737 // Add the outgoing port output action
738 //
739 FlowEntryAction flowEntryAction = new FlowEntryAction();
740 flowEntryAction.setActionOutput(newFlowEntry.outPort());
741 flowEntryActions.addAction(flowEntryAction);
742
743 //
744 // Set the state of the new Flow Entry
745 //
746 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
747 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
748 finalFlowEntries.add(newFlowEntry);
749 }
750
751 //
752 // Replace the old Flow Entries with the new Flow Entries.
753 // Note that the Flow Entries that will be deleted are added at
754 // the end.
755 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800756 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700757 flowPath.dataPath().setFlowEntries(finalFlowEntries);
758
759 return hasChanged;
760 }
761
762 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700763 * Receive a notification that a Flow is added.
764 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700765 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700766 */
767 @Override
768 public void notificationRecvFlowAdded(FlowPath flowPath) {
769 EventEntry<FlowPath> eventEntry =
770 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
771 networkEvents.add(eventEntry);
772 }
773
774 /**
775 * Receive a notification that a Flow is removed.
776 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700777 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700778 */
779 @Override
780 public void notificationRecvFlowRemoved(FlowPath flowPath) {
781 EventEntry<FlowPath> eventEntry =
782 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
783 networkEvents.add(eventEntry);
784 }
785
786 /**
787 * Receive a notification that a Flow is updated.
788 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700789 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700790 */
791 @Override
792 public void notificationRecvFlowUpdated(FlowPath flowPath) {
793 // NOTE: The ADD and UPDATE events are processed in same way
794 EventEntry<FlowPath> eventEntry =
795 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
796 networkEvents.add(eventEntry);
797 }
798
799 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700800 * Receive a notification that a FlowEntry is added.
801 *
802 * @param flowEntry the FlowEntry that is added.
803 */
804 @Override
805 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
806 EventEntry<FlowEntry> eventEntry =
807 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
808 networkEvents.add(eventEntry);
809 }
810
811 /**
812 * Receive a notification that a FlowEntry is removed.
813 *
814 * @param flowEntry the FlowEntry that is removed.
815 */
816 @Override
817 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
818 EventEntry<FlowEntry> eventEntry =
819 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
820 networkEvents.add(eventEntry);
821 }
822
823 /**
824 * Receive a notification that a FlowEntry is updated.
825 *
826 * @param flowEntry the FlowEntry that is updated.
827 */
828 @Override
829 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
830 // NOTE: The ADD and UPDATE events are processed in same way
831 EventEntry<FlowEntry> eventEntry =
832 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
833 networkEvents.add(eventEntry);
834 }
835
836 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700837 * Receive a notification that a Topology Element is added.
838 *
839 * @param topologyElement the Topology Element that is added.
840 */
841 @Override
842 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
843 EventEntry<TopologyElement> eventEntry =
844 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
845 networkEvents.add(eventEntry);
846 }
847
848 /**
849 * Receive a notification that a Topology Element is removed.
850 *
851 * @param topologyElement the Topology Element that is removed.
852 */
853 @Override
854 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
855 EventEntry<TopologyElement> eventEntry =
856 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
857 networkEvents.add(eventEntry);
858 }
859
860 /**
861 * Receive a notification that a Topology Element is updated.
862 *
863 * @param topologyElement the Topology Element that is updated.
864 */
865 @Override
866 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
867 // NOTE: The ADD and UPDATE events are processed in same way
868 EventEntry<TopologyElement> eventEntry =
869 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
870 networkEvents.add(eventEntry);
871 }
872}