blob: cf9b67d0f57772b8d5d2036a3b6dde576c2ef99d [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;
Yuta HIGUCHId8c37242014-01-07 11:51:29 -080011import java.util.Timer;
12import java.util.TimerTask;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080013import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070014import java.util.concurrent.BlockingQueue;
15import java.util.concurrent.LinkedBlockingQueue;
16
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080017import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080018import net.floodlightcontroller.core.IOFSwitchListener;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070019import net.onrc.onos.datagrid.IDatagridService;
Yuta HIGUCHI337e46d2014-01-10 22:49:27 -080020import net.onrc.onos.graph.DBOperation;
21import net.onrc.onos.graph.GraphDBManager;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070022import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070023import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070024import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070025import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080026import net.onrc.onos.ofcontroller.util.Dpid;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070027import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070028import net.onrc.onos.ofcontroller.util.FlowEntry;
29import net.onrc.onos.ofcontroller.util.FlowEntryAction;
30import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070031import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070032import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
33import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
34import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070035import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070036import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070037import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080038import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080039import net.onrc.onos.ofcontroller.util.Port;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080040import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
41
42import com.esotericsoftware.kryo2.Kryo;
Yuta HIGUCHIe5ef3872014-01-07 12:35:59 -080043import com.tinkerpop.blueprints.impls.ramcloud.PerfMon;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070044
45import org.slf4j.Logger;
46import org.slf4j.LoggerFactory;
47
48/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070049 * Class for FlowPath Maintenance.
50 * This class listens for FlowEvents to:
51 * - Maintain a local cache of the Network Topology.
52 * - Detect FlowPaths impacted by Topology change.
53 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070054 */
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080055class FlowEventHandler extends Thread implements IFlowEventHandlerService,
56 IOFSwitchListener {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080057
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080058 private boolean enableOnrc2014MeasurementsFlows = true;
59 private boolean enableOnrc2014MeasurementsTopology = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080060
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070061 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070062 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070063
Yuta HIGUCHI337e46d2014-01-10 22:49:27 -080064 private DBOperation dbHandler;
Yuta HIGUCHId8c37242014-01-07 11:51:29 -080065
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070066 private FlowManager flowManager; // The Flow Manager to use
67 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070068 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080069 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070070
71 // The queue with Flow Path and Topology Element updates
72 private BlockingQueue<EventEntry<?>> networkEvents =
73 new LinkedBlockingQueue<EventEntry<?>>();
74
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070075 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070076 private List<EventEntry<TopologyElement>> topologyEvents =
77 new LinkedList<EventEntry<TopologyElement>>();
78 private List<EventEntry<FlowPath>> flowPathEvents =
79 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070080 private List<EventEntry<FlowEntry>> flowEntryEvents =
81 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2194d112014-01-10 13:36:00 -080082 private List<EventEntry<Pair<FlowId, Dpid>>> flowIdEvents =
83 new LinkedList<EventEntry<Pair<FlowId, Dpid>>>();
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080084 private List<EventEntry<Pair<FlowEntryId, Dpid>>> flowEntryIdEvents =
85 new LinkedList<EventEntry<Pair<FlowEntryId, Dpid>>>();
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080086 private List<EventEntry<Dpid>> switchDpidEvents =
87 new LinkedList<EventEntry<Dpid>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070088
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080089 // All internally computed Flow Paths
90 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
91
92 // The Flow Entries received as notifications with unmatched Flow Paths
93 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
94 new HashMap<Long, FlowEntry>();
95
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080096 //
97 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080098 // - The Flow Paths that should be recomputed
99 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800100 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800101 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800102 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
103 new HashMap<Long, FlowPath>();
104 private Map<Long, FlowPath> modifiedFlowPaths =
105 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800106 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
107 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800108
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700109 /**
110 * Constructor for a given Flow Manager and Datagrid Service.
111 *
112 * @param flowManager the Flow Manager to use.
113 * @param datagridService the Datagrid Service to use.
114 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700115 FlowEventHandler(FlowManager flowManager,
116 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700117 this.flowManager = flowManager;
118 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700119 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700120 }
121
122 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800123 * Get the network topology.
124 *
125 * @return the network topology.
126 */
127 protected Topology getTopology() { return this.topology; }
128
129 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800130 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700131 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800132 private void startup() {
Yuta HIGUCHI337e46d2014-01-10 22:49:27 -0800133 this.dbHandler = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800134
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700135 //
136 // Obtain the initial Topology state
137 //
138 Collection<TopologyElement> topologyElements =
139 datagridService.getAllTopologyElements();
140 for (TopologyElement topologyElement : topologyElements) {
141 EventEntry<TopologyElement> eventEntry =
142 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
143 topologyEvents.add(eventEntry);
144 }
145 //
146 // Obtain the initial Flow Path state
147 //
148 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
149 for (FlowPath flowPath : flowPaths) {
150 EventEntry<FlowPath> eventEntry =
151 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
152 flowPathEvents.add(eventEntry);
153 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700154 //
155 // Obtain the initial FlowEntry state
156 //
157 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
158 for (FlowEntry flowEntry : flowEntries) {
159 EventEntry<FlowEntry> eventEntry =
160 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
161 flowEntryEvents.add(eventEntry);
162 }
163
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800164 //
165 // Obtain the initial FlowId state
166 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800167 Collection<Pair<FlowId, Dpid>> flowIds =
168 datagridService.getAllFlowIds();
169 for (Pair<FlowId, Dpid> pair : flowIds) {
170 EventEntry<Pair<FlowId, Dpid>> eventEntry =
171 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800172 flowIdEvents.add(eventEntry);
173 }
174
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800175 //
176 // Obtain the initial FlowEntryId state
177 //
178 Collection<Pair<FlowEntryId, Dpid>> flowEntryIds =
179 datagridService.getAllFlowEntryIds();
180 for (Pair<FlowEntryId, Dpid> pair : flowEntryIds) {
181 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
182 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
183 flowEntryIdEvents.add(eventEntry);
184 }
185
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800186 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800187 synchronized (allFlowPaths) {
188 processEvents();
189 }
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800190
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800191 }
192
193 /**
194 * Run the thread.
195 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800196 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800197 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800198 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800199 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700200
201 //
202 // The main loop
203 //
204 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
205 try {
206 while (true) {
207 EventEntry<?> eventEntry = networkEvents.take();
208 collection.add(eventEntry);
209 networkEvents.drainTo(collection);
210
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700211 //
212 // Demultiplex all events:
213 // - EventEntry<TopologyElement>
214 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700215 // - EventEntry<FlowEntry>
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800216 // - EventEntry<Pair<FlowId, Dpid>>
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800217 // - EventEntry<Pair<FlowEntryId, Dpid>>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700218 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700219 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800220 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700221 if (event.eventData() instanceof TopologyElement) {
222 EventEntry<TopologyElement> topologyEventEntry =
223 (EventEntry<TopologyElement>)event;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800224
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700225 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800226 continue;
227 }
228
229 // FlowPath event
230 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700231 EventEntry<FlowPath> flowPathEventEntry =
232 (EventEntry<FlowPath>)event;
233 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800234 continue;
235 }
236
237 // FlowEntry event
238 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700239 EventEntry<FlowEntry> flowEntryEventEntry =
240 (EventEntry<FlowEntry>)event;
241 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800242 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700243 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800244
245 // FlowId event
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800246 if (event.eventData() instanceof Pair) {
247 EventEntry<Pair<FlowId, Dpid>> flowIdEventEntry =
248 (EventEntry<Pair<FlowId, Dpid>>)event;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800249 flowIdEvents.add(flowIdEventEntry);
250 continue;
251 }
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800252
253 // Switch Dpid event
254 if (event.eventData() instanceof Dpid) {
255 EventEntry<Dpid> switchDpidEventEntry =
256 (EventEntry<Dpid>)event;
257 switchDpidEvents.add(switchDpidEventEntry);
258 continue;
259 }
260
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800261 // FlowEntryId event
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800262 // TODO: Fix the code below if we need again to handle
263 // the FlowEntryId events
264 /*
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800265 if (event.eventData() instanceof Pair) {
266 EventEntry<Pair<FlowEntryId, Dpid>> flowEntryIdEventEntry =
267 (EventEntry<Pair<FlowEntryId, Dpid>>)event;
268 flowEntryIdEvents.add(flowEntryIdEventEntry);
269 continue;
270 }
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800271 */
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700272 }
273 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700274
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700275 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800276 synchronized (allFlowPaths) {
277 processEvents();
278 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700279 }
280 } catch (Exception exception) {
281 log.debug("Exception processing Network Events: ", exception);
282 }
283 }
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800284
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700285 /**
286 * Process the events (if any)
287 */
288 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800289 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700290
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800291 if (enableOnrc2014MeasurementsFlows) {
292
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800293 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty() &&
294 switchDpidEvents.isEmpty()) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800295 return; // Nothing to do
296 }
297
298 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
299
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800300 // Process the Switch Dpid events
301 processSwitchDpidEvents();
302
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800303 // Process the Flow ID events
304 processFlowIdEvents(mySwitches);
305
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800306 // Fetch the topology
307 processTopologyEvents();
308
309 // Recompute all affected Flow Paths and keep only the modified
310 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
311 if (recomputeFlowPath(flowPath))
312 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
313 }
314
315 // Assign the Flow Entry ID as needed
316 for (FlowPath flowPath : modifiedFlowPaths.values()) {
317 for (FlowEntry flowEntry : flowPath.flowEntries()) {
318 if (! flowEntry.isValidFlowEntryId()) {
319 long id = flowManager.getNextFlowEntryId();
320 flowEntry.setFlowEntryId(new FlowEntryId(id));
321 }
322 }
323 }
324
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800325 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800326 // Push the modified state to the database
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800327 //
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800328 for (FlowPath flowPath : modifiedFlowPaths.values()) {
329 //
330 // Delete the Flow Path from the Network Map
331 //
332 if (flowPath.flowPathUserState() ==
333 FlowPathUserState.FP_USER_DELETE) {
334 log.debug("Deleting Flow Path From Database: {}", flowPath);
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800335 // TODO: For now the deleting of a Flow Path is blocking
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800336 ParallelFlowDatabaseOperation.deleteFlow(dbHandler,
Pavlin Radoslavov6c3e6802014-01-10 19:27:34 -0800337 flowPath.flowId());
338 // Send the notifications for the deleted Flow Entries
339 for (FlowEntry flowEntry : flowPath.flowEntries()) {
340 datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
341 }
342
Pavlin Radoslavov85d81c02014-01-10 17:22:22 -0800343 continue;
344 }
345
346 log.debug("Pushing Flow Path To Database: {}", flowPath);
347 //
348 // Write the Flow Path to the Network Map
349 //
350 ParallelFlowDatabaseOperation.addFlow(dbHandler, flowPath,
351 datagridService);
352 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800353
354 // Cleanup
355 topologyEvents.clear();
356 flowIdEvents.clear();
Pavlin Radoslavov2d6e5f12014-01-10 16:34:05 -0800357 switchDpidEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800358 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800359 // NOTE: Keep a cache with my Flow Paths
360 // allFlowPaths.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800361 shouldRecomputeFlowPaths.clear();
362 modifiedFlowPaths.clear();
363
364 return;
365 }
366
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700367 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
368 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700369 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700370 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700371
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800372 processFlowPathEvents();
373 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800374 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800375 processFlowEntryEvents();
376
377 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800378 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800379 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800380 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800381 }
382
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800383 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800384 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800385
386 // Assign missing Flow Entry IDs
387 assignFlowEntryId(modifiedFlowEntries);
388
389 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800390 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800391 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800392 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
393 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800394
395 //
396 // Remove Flow Entries that were deleted
397 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800398 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800399 flowPath.dataPath().removeDeletedFlowEntries();
400
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800401 //
402 // Check if Flow Paths have been installed into all switches,
403 // and generate the appropriate events.
404 //
405 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
406
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800407 // Cleanup
408 topologyEvents.clear();
409 flowPathEvents.clear();
410 flowEntryEvents.clear();
411 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800412 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800413 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800414 checkIfInstalledFlowPaths.clear();
415 }
416
417 /**
418 * Check if Flow Paths have been installed into all switches,
419 * and generate the appropriate events.
420 *
421 * @param flowPaths the flowPaths to process.
422 */
423 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
424 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
425
426 Kryo kryo = kryoFactory.newKryo();
427
428 for (FlowPath flowPath : flowPaths) {
429 boolean isInstalled = true;
430
431 //
432 // Check whether all Flow Entries have been installed
433 //
434 for (FlowEntry flowEntry : flowPath.flowEntries()) {
435 if (flowEntry.flowEntrySwitchState() !=
436 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
437 isInstalled = false;
438 break;
439 }
440 }
441
442 if (isInstalled) {
443 // Create a copy and add it to the list
444 FlowPath copyFlowPath = kryo.copy(flowPath);
445 installedFlowPaths.add(copyFlowPath);
446 }
447 }
448 kryoFactory.deleteKryo(kryo);
449
450 // Generate an event for the installed Flow Path.
451 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800452 }
453
454 /**
455 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800456 *
457 * @param modifiedFlowPaths the Flow Paths to process.
458 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800459 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800460 private Collection<FlowEntry> extractModifiedFlowEntries(
461 Collection<FlowPath> modifiedFlowPaths) {
462 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800463
464 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800465 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800466 for (FlowEntry flowEntry : flowPath.flowEntries()) {
467 if (flowEntry.flowEntrySwitchState() ==
468 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800469 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800470 }
471 }
472 }
473 return modifiedFlowEntries;
474 }
475
476 /**
477 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800478 *
479 * @param modifiedFlowEnries the collection of Flow Entries that need
480 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800481 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800482 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800483 if (modifiedFlowEntries.isEmpty())
484 return;
485
486 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
487
488 //
489 // Assign the Flow Entry ID only for Flow Entries for my switches
490 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800491 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800492 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
493 if (mySwitch == null)
494 continue;
495 if (! flowEntry.isValidFlowEntryId()) {
496 long id = flowManager.getNextFlowEntryId();
497 flowEntry.setFlowEntryId(new FlowEntryId(id));
498 }
499 }
500 }
501
502 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800503 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800504 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800505 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800506 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800507 private void fixFlowFromDatabase(FlowPath flowPath) {
508 //
509 // TODO: Bug workaround / fix :
510 // method FlowDatabaseOperation.extractFlowEntry() doesn't
511 // fetch the inPort and outPort, hence we assign them here.
512 //
513 // Assign the inPort and outPort for the Flow Entries
514 for (FlowEntry flowEntry : flowPath.flowEntries()) {
515 // Set the inPort
516 do {
517 if (flowEntry.inPort() != null)
518 break;
519 if (flowEntry.flowEntryMatch() == null)
520 break;
521 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
522 flowEntry.setInPort(inPort);
523 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800524
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800525 // Set the outPort
526 do {
527 if (flowEntry.outPort() != null)
528 break;
529 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
530 if (fa.actionOutput() != null) {
531 Port outPort = new Port(fa.actionOutput().port().value());
532 flowEntry.setOutPort(outPort);
533 break;
534 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800535 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800536 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800537 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800538 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800539
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800540 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800541 * Process the Switch Dpid events.
542 */
543 private void processSwitchDpidEvents() {
544 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
545 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
546
547 //
548 // Process all Switch Dpid events and update the appropriate state
549 //
550 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
551 Dpid dpid = eventEntry.eventData();
552
553 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
554
555 // Compute the final set of added and removed switches
556 switch (eventEntry.eventType()) {
557 case ENTRY_ADD:
558 addedSwitches.put(dpid.value(), dpid);
559 removedSwitches.remove(dpid.value());
560 break;
561 case ENTRY_REMOVE:
562 addedSwitches.remove(dpid.value());
563 removedSwitches.put(dpid.value(), dpid);
564 break;
565 }
566 }
567
568 //
569 // Remove the Flows from the local cache if the removed
570 // switch is the Source Switch.
571 //
572 // TODO: This search can be expensive for a large number of flows
573 // and should be optmized.
574 //
575 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
576 for (Dpid switchDpid : removedSwitches.values()) {
577 for (FlowPath flowPath : allFlowPaths.values()) {
578 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
579 if (srcDpid.value() == switchDpid.value())
580 deleteFlowIds.add(flowPath.flowId());
581 }
582 }
583 //
584 // Remove the Flows from the local cache
585 //
586 for (FlowId flowId : deleteFlowIds)
587 allFlowPaths.remove(flowId.value());
588
589 // Get the Flows for the added switches
590 Collection<FlowPath> flowPaths =
591 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
592 addedSwitches.values());
593 for (FlowPath flowPath : flowPaths) {
594 allFlowPaths.put(flowPath.flowId().value(), flowPath);
595 }
596 }
597
598 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800599 * Process the Flow ID events.
600 *
601 * @param mySwitches the collection of my switches.
602 */
603 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800604 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
605
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800606 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800607 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800608 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800609 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
610 Pair<FlowId, Dpid> pair = eventEntry.eventData();
611 FlowId flowId = pair.first;
612 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800613
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800614 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
615 flowId, dpid);
616
617 //
618 // Ignore Flows if the Source Switch is not controlled by this
619 // instance.
620 //
621 if (mySwitches.get(dpid.value()) == null)
622 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800623
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800624 switch (eventEntry.eventType()) {
625 case ENTRY_ADD: {
626 //
627 // Add a new Flow Path
628 //
629 if (allFlowPaths.get(flowId.value()) != null) {
630 //
631 // TODO: What to do if the Flow Path already exists?
632 // Fow now, we just re-add it.
633 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800634 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800635 shouldFetchMyFlowIds.add(flowId);
636
637 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800638 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800639
640 case ENTRY_REMOVE: {
641 //
642 // Remove an existing Flow Path.
643 //
644 // Find the Flow Path, and mark the Flow and its Flow Entries
645 // for deletion.
646 //
647 FlowPath existingFlowPath =
648 allFlowPaths.get(flowId.value());
649 if (existingFlowPath == null)
650 continue; // Nothing to do
651
652 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
653 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
654 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
655 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
656 }
657
658 // Remove the Flow Path from the internal state
659 Long key = existingFlowPath.flowId().value();
660 allFlowPaths.remove(key);
661 shouldRecomputeFlowPaths.remove(key);
662 modifiedFlowPaths.put(key, existingFlowPath);
663
664 break;
665 }
666 }
667 }
668
669 // Get my Flows
670 Collection<FlowPath> myFlows =
Pavlin Radoslavov6602b6a2014-01-10 16:43:29 -0800671 ParallelFlowDatabaseOperation.getFlows(dbHandler,
672 shouldFetchMyFlowIds);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800673
674 for (FlowPath flowPath : myFlows) {
675 fixFlowFromDatabase(flowPath);
676
677 switch (flowPath.flowPathType()) {
678 case FP_TYPE_SHORTEST_PATH:
679 //
680 // Reset the Data Path, in case it was set already, because
681 // we are going to recompute it anyway.
682 //
683 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800684 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
685 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800686 break;
687 case FP_TYPE_EXPLICIT_PATH:
688 //
689 // Mark all Flow Entries for installation in the switches.
690 //
691 for (FlowEntry flowEntry : flowPath.flowEntries()) {
692 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
693 }
694 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
695 break;
696 case FP_TYPE_UNKNOWN:
697 log.error("FlowPath event with unknown type");
698 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800699 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800700 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800701 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800702 }
703
704 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800705 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800706 *
707 * @param mySwitches the collection of my switches.
708 * @return a collection of modified Flow Entries this instance needs
709 * to push to its own switches.
710 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800711 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800712 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
713
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800714 //
715 // Process all Flow ID events and update the appropriate state
716 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800717 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
718 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
719 FlowEntryId flowEntryId = pair.first;
720 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800721
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800722 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
723 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800724
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800725 if (mySwitches.get(dpid.value()) == null)
726 continue;
727
728 // Fetch the Flow Entry
729 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
730 flowEntryId);
731 if (flowEntry == null) {
732 log.debug("Flow Entry ID {} : Flow Entry not found!",
733 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800734 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800735 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800736 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800737 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800738
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800739 return modifiedFlowEntries;
740 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800741
742 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800743 * Process the Flow Path events.
744 */
745 private void processFlowPathEvents() {
746 //
747 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700748 //
749 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
750 FlowPath flowPath = eventEntry.eventData();
751
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800752 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800753
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700754 switch (eventEntry.eventType()) {
755 case ENTRY_ADD: {
756 //
757 // Add a new Flow Path
758 //
759 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
760 //
761 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800762 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700763 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700764 }
765
766 switch (flowPath.flowPathType()) {
767 case FP_TYPE_SHORTEST_PATH:
768 //
769 // Reset the Data Path, in case it was set already, because
770 // we are going to recompute it anyway.
771 //
772 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800773 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
774 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700775 break;
776 case FP_TYPE_EXPLICIT_PATH:
777 //
778 // Mark all Flow Entries for installation in the switches.
779 //
780 for (FlowEntry flowEntry : flowPath.flowEntries()) {
781 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
782 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800783 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700784 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800785 case FP_TYPE_UNKNOWN:
786 log.error("FlowPath event with unknown type");
787 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700788 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800789 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700790
791 break;
792 }
793
794 case ENTRY_REMOVE: {
795 //
796 // Remove an existing Flow Path.
797 //
798 // Find the Flow Path, and mark the Flow and its Flow Entries
799 // for deletion.
800 //
801 FlowPath existingFlowPath =
802 allFlowPaths.get(flowPath.flowId().value());
803 if (existingFlowPath == null)
804 continue; // Nothing to do
805
806 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
807 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
808 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
809 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
810 }
811
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800812 // Remove the Flow Path from the internal state
813 Long key = existingFlowPath.flowId().value();
814 allFlowPaths.remove(key);
815 shouldRecomputeFlowPaths.remove(key);
816 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700817
818 break;
819 }
820 }
821 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800822 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700823
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800824 /**
825 * Process the Topology events.
826 */
827 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800828 boolean isTopologyModified = false;
829
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800830 if (enableOnrc2014MeasurementsTopology) {
831 if (topologyEvents.isEmpty())
832 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800833
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800834 // TODO: Code for debugging purpose only
835 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
836 TopologyElement topologyElement = eventEntry.eventData();
837 log.debug("Topology Event: {} {}", eventEntry.eventType(),
838 topologyElement.toString());
839 }
840
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800841 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800842 topology.readFromDatabase(dbHandler);
843 log.debug("[AFTER] {}", topology.toString());
844 shouldRecomputeFlowPaths.putAll(allFlowPaths);
845 return;
846 }
847
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700848 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800849 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700850 //
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700851 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
852 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800853
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800854 log.debug("Topology Event: {} {}", eventEntry.eventType(),
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800855 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800856
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700857 switch (eventEntry.eventType()) {
858 case ENTRY_ADD:
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800859 synchronized (topology) {
860 isTopologyModified |= topology.addTopologyElement(topologyElement);
861 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700862 break;
863 case ENTRY_REMOVE:
Yuta HIGUCHId8c37242014-01-07 11:51:29 -0800864 synchronized (topology) {
865 isTopologyModified |= topology.removeTopologyElement(topologyElement);
866 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700867 break;
868 }
869 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700870 if (isTopologyModified) {
871 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800872 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700873 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800874 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700875
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800876 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800877 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800878 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800879 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800880 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800881 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800882
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700883 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800884 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700885 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800886 if (! unmatchedFlowEntryAdd.isEmpty()) {
887 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
888 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800889 // log.debug("Processing Unmatched Flow Entry: {}",
890 // flowEntry.toString());
891
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800892 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800893 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800894 remainingUpdates.put(flowEntry.flowEntryId().value(),
895 flowEntry);
896 continue;
897 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800898 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
899 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800900 remainingUpdates.put(flowEntry.flowEntryId().value(),
901 flowEntry);
902 continue;
903 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800904 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
905 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
906 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700907 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800908 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700909 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800910 }
911
912 /**
913 * Process the Flow Entry events.
914 */
915 private void processFlowEntryEvents() {
916 FlowPath flowPath;
917 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700918
919 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800920 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700921 //
922 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
923 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800924
925 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800926 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800927
928 if ((! flowEntry.isValidFlowId()) ||
929 (! flowEntry.isValidFlowEntryId())) {
930 continue;
931 }
932
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700933 switch (eventEntry.eventType()) {
934 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800935 flowPath = allFlowPaths.get(flowEntry.flowId().value());
936 if (flowPath == null) {
937 // Flow Path not found: keep the entry for later matching
938 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
939 flowEntry);
940 break;
941 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800942 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
943 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800944 // Flow Entry not found: keep the entry for later matching
945 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
946 flowEntry);
947 break;
948 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800949 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
950 // Add the updated Flow Path to the list of updated paths
951 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
952 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700953 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800954
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700955 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800956 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
957 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800958 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800959 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800960
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800961 flowPath = allFlowPaths.get(flowEntry.flowId().value());
962 if (flowPath == null) {
963 // Flow Path not found: ignore the update
964 break;
965 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800966 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
967 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800968 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800969 break;
970 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800971 if (updateFlowEntryRemove(flowPath, localFlowEntry,
972 flowEntry)) {
973 // Add the updated Flow Path to the list of updated paths
974 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
975 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700976 break;
977 }
978 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700979 }
980
981 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800982 * Find a Flow Entry that should be updated because of an external
983 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700984 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800985 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800986 * @param newFlowEntry the FlowEntry with the new state.
987 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700988 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800989 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
990 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700991 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800992 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700993 //
994 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800995 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800996 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700997 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800998 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700999
1000 //
1001 // Local Flow Entry match found
1002 //
1003 if (localFlowEntry.isValidFlowEntryId()) {
1004 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001005 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001006 //
1007 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001008 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001009 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001010 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001011 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001012 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001013 return localFlowEntry;
1014 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001015
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001016 return null; // Entry not found
1017 }
1018
1019 /**
1020 * Update a Flow Entry because of an external ENTRY_ADD event.
1021 *
1022 * @param flowPath the FlowPath for the Flow Entry to update.
1023 * @param localFlowEntry the local Flow Entry to update.
1024 * @param newFlowEntry the FlowEntry with the new state.
1025 * @return true if the local Flow Entry was updated, otherwise false.
1026 */
1027 private boolean updateFlowEntryAdd(FlowPath flowPath,
1028 FlowEntry localFlowEntry,
1029 FlowEntry newFlowEntry) {
1030 boolean updated = false;
1031
1032 if (localFlowEntry.flowEntryUserState() ==
1033 FlowEntryUserState.FE_USER_DELETE) {
1034 // Don't add-back a Flow Entry that is already deleted
1035 return false;
1036 }
1037
1038 if (! localFlowEntry.isValidFlowEntryId()) {
1039 // Update the Flow Entry ID
1040 FlowEntryId flowEntryId =
1041 new FlowEntryId(newFlowEntry.flowEntryId().value());
1042 localFlowEntry.setFlowEntryId(flowEntryId);
1043 updated = true;
1044 }
1045
1046 //
1047 // Update the local Flow Entry, and keep state to check
1048 // if the Flow Path has been installed.
1049 //
1050 if (localFlowEntry.flowEntryUserState() !=
1051 newFlowEntry.flowEntryUserState()) {
1052 localFlowEntry.setFlowEntryUserState(
1053 newFlowEntry.flowEntryUserState());
1054 updated = true;
1055 }
1056 if (localFlowEntry.flowEntrySwitchState() !=
1057 newFlowEntry.flowEntrySwitchState()) {
1058 localFlowEntry.setFlowEntrySwitchState(
1059 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001060 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001061 updated = true;
1062 }
1063
1064 return updated;
1065 }
1066
1067 /**
1068 * Find a Flow Entry that should be updated because of an external
1069 * ENTRY_REMOVE event.
1070 *
1071 * @param flowPath the FlowPath for the Flow Entry to update.
1072 * @param newFlowEntry the FlowEntry with the new state.
1073 * @return the Flow Entry that should be updated if found, otherwise null.
1074 */
1075 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1076 FlowEntry newFlowEntry) {
1077 //
1078 // Iterate over all Flow Entries and find a match based on
1079 // the Flow Entry ID.
1080 //
1081 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1082 if (! localFlowEntry.isValidFlowEntryId())
1083 continue;
1084 if (localFlowEntry.flowEntryId().value() !=
1085 newFlowEntry.flowEntryId().value()) {
1086 continue;
1087 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001088 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001089 }
1090
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001091 return null; // Entry not found
1092 }
1093
1094 /**
1095 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1096 *
1097 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001098 * @param localFlowEntry the local Flow Entry to update.
1099 * @param newFlowEntry the FlowEntry with the new state.
1100 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001101 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001102 private boolean updateFlowEntryRemove(FlowPath flowPath,
1103 FlowEntry localFlowEntry,
1104 FlowEntry newFlowEntry) {
1105 boolean updated = false;
1106
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001107 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001108 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001109 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001110 if (localFlowEntry.flowEntryUserState() !=
1111 newFlowEntry.flowEntryUserState()) {
1112 localFlowEntry.setFlowEntryUserState(
1113 newFlowEntry.flowEntryUserState());
1114 updated = true;
1115 }
1116 if (localFlowEntry.flowEntrySwitchState() !=
1117 newFlowEntry.flowEntrySwitchState()) {
1118 localFlowEntry.setFlowEntrySwitchState(
1119 newFlowEntry.flowEntrySwitchState());
1120 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001121 }
1122
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001123 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001124 }
1125
1126 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001127 * Recompute a Flow Path.
1128 *
1129 * @param flowPath the Flow Path to recompute.
1130 * @return true if the recomputed Flow Path has changed, otherwise false.
1131 */
1132 private boolean recomputeFlowPath(FlowPath flowPath) {
1133 boolean hasChanged = false;
1134
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001135 if (enableOnrc2014MeasurementsFlows) {
1136 // Cleanup the deleted Flow Entries from the earlier iteration
1137 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001138
1139 //
1140 // TODO: Fake it that the Flow Entries have been already pushed
1141 // into the switches, so we don't push them again.
1142 //
1143 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1144 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1145 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001146 }
1147
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001148 //
1149 // Test whether the Flow Path needs to be recomputed
1150 //
1151 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001152 case FP_TYPE_UNKNOWN:
1153 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001154 case FP_TYPE_SHORTEST_PATH:
1155 break;
1156 case FP_TYPE_EXPLICIT_PATH:
1157 return false; // An explicit path never changes
1158 }
1159
1160 DataPath oldDataPath = flowPath.dataPath();
1161
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001162 // Compute the new path
Yuta HIGUCHId8c37242014-01-07 11:51:29 -08001163 DataPath newDataPath;
1164 synchronized (topology) {
1165 newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001166 flowPath);
Yuta HIGUCHId8c37242014-01-07 11:51:29 -08001167 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001168 if (newDataPath == null) {
1169 // We need the DataPath to compare the paths
1170 newDataPath = new DataPath();
1171 }
1172 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1173
1174 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001175 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001176 //
1177 if (oldDataPath.flowEntries().size() !=
1178 newDataPath.flowEntries().size()) {
1179 hasChanged = true;
1180 } else {
1181 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1182 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1183 while (oldIter.hasNext() && newIter.hasNext()) {
1184 FlowEntry oldFlowEntry = oldIter.next();
1185 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001186 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1187 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001188 hasChanged = true;
1189 break;
1190 }
1191 }
1192 }
1193 if (! hasChanged)
1194 return hasChanged;
1195
1196 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001197 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001198 // - If a Flow Entry for a switch is in the old data path, but not
1199 // in the new data path, then mark it for deletion.
1200 // - If a Flow Entry for a switch is in the new data path, but not
1201 // in the old data path, then mark it for addition.
1202 // - If a Flow Entry for a switch is in both the old and the new
1203 // data path, but it has changed, e.g., the incoming and/or outgoing
1204 // port(s), then mark the old Flow Entry for deletion, and mark
1205 // the new Flow Entry for addition.
1206 // - If a Flow Entry for a switch is in both the old and the new
1207 // data path, and it hasn't changed, then just keep it.
1208 //
1209 // NOTE: We use the Switch DPID of each entry to match the entries
1210 //
1211 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1212 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1213 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1214 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1215
1216 // Prepare maps with the Flow Entries, so they are fast to lookup
1217 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1218 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1219 for (FlowEntry flowEntry : newDataPath.flowEntries())
1220 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1221
1222 //
1223 // Find the old Flow Entries that should be deleted
1224 //
1225 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1226 FlowEntry newFlowEntry =
1227 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1228 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001229 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001230 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1231 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1232 deletedFlowEntries.add(oldFlowEntry);
1233 }
1234 }
1235
1236 //
1237 // Find the new Flow Entries that should be added or updated
1238 //
1239 int idx = 0;
1240 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1241 FlowEntry oldFlowEntry =
1242 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1243
1244 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001245 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1246 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001247 //
1248 // Both Flow Entries are same
1249 //
1250 finalFlowEntries.add(oldFlowEntry);
1251 idx++;
1252 continue;
1253 }
1254
1255 if (oldFlowEntry != null) {
1256 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001257 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001258 //
1259 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1260 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1261 deletedFlowEntries.add(oldFlowEntry);
1262 }
1263
1264 //
1265 // Add the new Flow Entry
1266 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001267 //
1268 // NOTE: Assign only the Flow ID.
1269 // The Flow Entry ID is assigned later only for the Flow Entries
1270 // this instance is responsible for.
1271 //
1272 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001273
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001274 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001275 // Copy the Flow timeouts
1276 //
1277 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1278 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1279
1280 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001281 // Allocate the FlowEntryMatch by copying the default one
1282 // from the FlowPath (if set).
1283 //
1284 FlowEntryMatch flowEntryMatch = null;
1285 if (flowPath.flowEntryMatch() != null)
1286 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1287 else
1288 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001289 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001290
1291 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001292 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1293
1294 //
1295 // Set the actions:
1296 // If the first Flow Entry, copy the Flow Path actions to it.
1297 //
1298 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1299 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1300 FlowEntryActions flowActions =
1301 new FlowEntryActions(flowPath.flowEntryActions());
1302 for (FlowEntryAction action : flowActions.actions())
1303 flowEntryActions.addAction(action);
1304 }
1305 idx++;
1306
1307 //
1308 // Add the outgoing port output action
1309 //
1310 FlowEntryAction flowEntryAction = new FlowEntryAction();
1311 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1312 flowEntryActions.addAction(flowEntryAction);
1313
1314 //
1315 // Set the state of the new Flow Entry
1316 //
1317 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1318 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1319 finalFlowEntries.add(newFlowEntry);
1320 }
1321
1322 //
1323 // Replace the old Flow Entries with the new Flow Entries.
1324 // Note that the Flow Entries that will be deleted are added at
1325 // the end.
1326 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001327 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001328 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1329
1330 return hasChanged;
1331 }
1332
1333 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001334 * Receive a notification that a Flow is added.
1335 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001336 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001337 */
1338 @Override
1339 public void notificationRecvFlowAdded(FlowPath flowPath) {
1340 EventEntry<FlowPath> eventEntry =
1341 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1342 networkEvents.add(eventEntry);
1343 }
1344
1345 /**
1346 * Receive a notification that a Flow is removed.
1347 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001348 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001349 */
1350 @Override
1351 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1352 EventEntry<FlowPath> eventEntry =
1353 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1354 networkEvents.add(eventEntry);
1355 }
1356
1357 /**
1358 * Receive a notification that a Flow is updated.
1359 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001360 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001361 */
1362 @Override
1363 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1364 // NOTE: The ADD and UPDATE events are processed in same way
1365 EventEntry<FlowPath> eventEntry =
1366 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1367 networkEvents.add(eventEntry);
1368 }
1369
1370 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001371 * Receive a notification that a FlowEntry is added.
1372 *
1373 * @param flowEntry the FlowEntry that is added.
1374 */
1375 @Override
1376 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001377 if (enableOnrc2014MeasurementsFlows) {
1378 Collection entries = new ArrayList();
1379 entries.add(flowEntry);
1380 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1381 return;
1382 }
1383
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001384 EventEntry<FlowEntry> eventEntry =
1385 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1386 networkEvents.add(eventEntry);
1387 }
1388
1389 /**
1390 * Receive a notification that a FlowEntry is removed.
1391 *
1392 * @param flowEntry the FlowEntry that is removed.
1393 */
1394 @Override
1395 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001396 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001397 //
1398 // NOTE: Must update the state to DELETE, because
1399 // the notification contains the original state.
1400 //
1401 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1402
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001403 Collection entries = new ArrayList();
1404 entries.add(flowEntry);
1405 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1406 return;
1407 }
1408
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001409 EventEntry<FlowEntry> eventEntry =
1410 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1411 networkEvents.add(eventEntry);
1412 }
1413
1414 /**
1415 * Receive a notification that a FlowEntry is updated.
1416 *
1417 * @param flowEntry the FlowEntry that is updated.
1418 */
1419 @Override
1420 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001421 if (enableOnrc2014MeasurementsFlows) {
1422 Collection entries = new ArrayList();
1423 entries.add(flowEntry);
1424 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1425 return;
1426 }
1427
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001428 // NOTE: The ADD and UPDATE events are processed in same way
1429 EventEntry<FlowEntry> eventEntry =
1430 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1431 networkEvents.add(eventEntry);
1432 }
1433
1434 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001435 * Receive a notification that a FlowId is added.
1436 *
1437 * @param flowId the FlowId that is added.
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 notificationRecvFlowIdAdded(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_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001446 networkEvents.add(eventEntry);
1447 }
1448
1449 /**
1450 * Receive a notification that a FlowId is removed.
1451 *
1452 * @param flowId the FlowId that is removed.
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 notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1457 Pair flowIdPair = new Pair(flowId, dpid);
1458
1459 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1460 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001461 networkEvents.add(eventEntry);
1462 }
1463
1464 /**
1465 * Receive a notification that a FlowId is updated.
1466 *
1467 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001468 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001469 */
1470 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001471 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1472 Pair flowIdPair = new Pair(flowId, dpid);
1473
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001474 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001475 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1476 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001477 networkEvents.add(eventEntry);
1478 }
1479
1480 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001481 * Receive a notification that a FlowEntryId is added.
1482 *
1483 * @param flowEntryId the FlowEntryId that is added.
1484 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1485 */
1486 @Override
1487 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1488 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001489 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1490
1491 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1492 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001493 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001494 }
1495
1496 /**
1497 * Receive a notification that a FlowEntryId is removed.
1498 *
1499 * @param flowEntryId the FlowEntryId that is removed.
1500 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1501 */
1502 @Override
1503 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1504 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001505 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1506
1507 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1508 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001509 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001510 }
1511
1512 /**
1513 * Receive a notification that a FlowEntryId is updated.
1514 *
1515 * @param flowEntryId the FlowEntryId that is updated.
1516 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1517 */
1518 @Override
1519 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1520 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001521 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1522
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001523 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001524 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1525 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001526 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001527 }
1528
1529 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001530 * Receive a notification that a Topology Element is added.
1531 *
1532 * @param topologyElement the Topology Element that is added.
1533 */
1534 @Override
1535 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1536 EventEntry<TopologyElement> eventEntry =
1537 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1538 networkEvents.add(eventEntry);
1539 }
1540
1541 /**
1542 * Receive a notification that a Topology Element is removed.
1543 *
1544 * @param topologyElement the Topology Element that is removed.
1545 */
1546 @Override
1547 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1548 EventEntry<TopologyElement> eventEntry =
1549 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1550 networkEvents.add(eventEntry);
1551 }
1552
1553 /**
1554 * Receive a notification that a Topology Element is updated.
1555 *
1556 * @param topologyElement the Topology Element that is updated.
1557 */
1558 @Override
1559 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1560 // NOTE: The ADD and UPDATE events are processed in same way
1561 EventEntry<TopologyElement> eventEntry =
1562 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1563 networkEvents.add(eventEntry);
1564 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001565
1566 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001567 * Receive a notification that a switch is added to this instance.
1568 *
1569 * @param sw the switch that is added.
1570 */
1571 @Override
1572 public void addedSwitch(IOFSwitch sw) {
1573 Dpid dpid = new Dpid(sw.getId());
1574 EventEntry<Dpid> eventEntry =
1575 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1576 networkEvents.add(eventEntry);
1577 }
1578
1579 /**
1580 * Receive a notification that a switch is removed from this instance.
1581 *
1582 * @param sw the switch that is removed.
1583 */
1584 @Override
1585 public void removedSwitch(IOFSwitch sw) {
1586 Dpid dpid = new Dpid(sw.getId());
1587 EventEntry<Dpid> eventEntry =
1588 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1589 networkEvents.add(eventEntry);
1590 }
1591
1592 /**
1593 * Receive a notification that the ports on a switch have changed.
1594 */
1595 @Override
1596 public void switchPortChanged(Long switchId) {
1597 // Nothing to do
1598 }
1599
1600 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001601 * Get a sorted copy of all Flow Paths.
1602 *
1603 * @return a sorted copy of all Flow Paths.
1604 */
1605 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1606 SortedMap<Long, FlowPath> sortedFlowPaths =
1607 new TreeMap<Long, FlowPath>();
1608
1609 //
1610 // TODO: For now we use serialization/deserialization to create
1611 // a copy of each Flow Path. In the future, we should use proper
1612 // copy constructors.
1613 //
1614 Kryo kryo = kryoFactory.newKryo();
1615 synchronized (allFlowPaths) {
1616 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1617 FlowPath origFlowPath = entry.getValue();
1618 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1619 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1620 }
1621 }
1622 kryoFactory.deleteKryo(kryo);
1623
1624 return sortedFlowPaths;
1625 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001626}