blob: 5c095d5d85339f1d9b238a62e16c7a8369766550 [file] [log] [blame]
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
2
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07003import java.util.ArrayList;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07004import java.util.Collection;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07005import java.util.HashMap;
6import java.util.Iterator;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07007import java.util.LinkedList;
8import java.util.List;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07009import java.util.Map;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080010import java.util.SortedMap;
11import java.util.TreeMap;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.LinkedBlockingQueue;
14
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080015import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080016import net.floodlightcontroller.core.IOFSwitchListener;
17
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070018import net.onrc.onos.datagrid.IDatagridService;
Naoki Shiota0abe38d2014-01-07 15:31:22 -080019import net.onrc.onos.graph.GraphDBOperation;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070020import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070021import net.onrc.onos.ofcontroller.topology.TopologyElement;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070022import net.onrc.onos.ofcontroller.topology.TopologyManager;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070023import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080024import net.onrc.onos.ofcontroller.util.Dpid;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070025import net.onrc.onos.ofcontroller.util.EventEntry;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070026import net.onrc.onos.ofcontroller.util.FlowEntry;
27import net.onrc.onos.ofcontroller.util.FlowEntryAction;
28import net.onrc.onos.ofcontroller.util.FlowEntryActions;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070029import net.onrc.onos.ofcontroller.util.FlowEntryId;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070030import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
31import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
32import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -070033import net.onrc.onos.ofcontroller.util.FlowId;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070034import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -070035import net.onrc.onos.ofcontroller.util.FlowPathUserState;
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080036import net.onrc.onos.ofcontroller.util.Pair;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -080037import net.onrc.onos.ofcontroller.util.Port;
Pavlin Radoslavov53219802013-12-06 11:02:04 -080038import net.onrc.onos.ofcontroller.util.serializers.KryoFactory;
39
40import com.esotericsoftware.kryo2.Kryo;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070041
42import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
45/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070046 * Class for FlowPath Maintenance.
47 * This class listens for FlowEvents to:
48 * - Maintain a local cache of the Network Topology.
49 * - Detect FlowPaths impacted by Topology change.
50 * - Recompute impacted FlowPath using cached Topology.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070051 */
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080052class FlowEventHandler extends Thread implements IFlowEventHandlerService,
53 IOFSwitchListener {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080054
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -080055 private boolean enableOnrc2014MeasurementsFlows = true;
56 private boolean enableOnrc2014MeasurementsTopology = true;
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -080057
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070058 /** The logger. */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -070059 private final static Logger log = LoggerFactory.getLogger(FlowEventHandler.class);
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080060
Naoki Shiota0abe38d2014-01-07 15:31:22 -080061 private GraphDBOperation dbHandler;
Naoki Shiotaf74d5f32014-01-09 21:29:38 -080062
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070063 private FlowManager flowManager; // The Flow Manager to use
64 private IDatagridService datagridService; // The Datagrid Service to use
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070065 private Topology topology; // The network topology
Pavlin Radoslavov53219802013-12-06 11:02:04 -080066 private KryoFactory kryoFactory = new KryoFactory();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070067
68 // The queue with Flow Path and Topology Element updates
69 private BlockingQueue<EventEntry<?>> networkEvents =
70 new LinkedBlockingQueue<EventEntry<?>>();
71
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070072 // The pending Topology, FlowPath, and FlowEntry events
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070073 private List<EventEntry<TopologyElement>> topologyEvents =
74 new LinkedList<EventEntry<TopologyElement>>();
75 private List<EventEntry<FlowPath>> flowPathEvents =
76 new LinkedList<EventEntry<FlowPath>>();
Pavlin Radoslavovb7506842013-10-29 17:46:54 -070077 private List<EventEntry<FlowEntry>> flowEntryEvents =
78 new LinkedList<EventEntry<FlowEntry>>();
Pavlin Radoslavov2194d112014-01-10 13:36:00 -080079 private List<EventEntry<Pair<FlowId, Dpid>>> flowIdEvents =
80 new LinkedList<EventEntry<Pair<FlowId, Dpid>>>();
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -080081 private List<EventEntry<Pair<FlowEntryId, Dpid>>> flowEntryIdEvents =
82 new LinkedList<EventEntry<Pair<FlowEntryId, Dpid>>>();
Pavlin Radoslavovcc757162014-01-10 16:26:38 -080083 private List<EventEntry<Dpid>> switchDpidEvents =
84 new LinkedList<EventEntry<Dpid>>();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -070085
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080086 // All internally computed Flow Paths
87 private Map<Long, FlowPath> allFlowPaths = new HashMap<Long, FlowPath>();
88
89 // The Flow Entries received as notifications with unmatched Flow Paths
90 private Map<Long, FlowEntry> unmatchedFlowEntryAdd =
91 new HashMap<Long, FlowEntry>();
92
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080093 //
94 // Transient state for processing the Flow Paths:
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080095 // - The Flow Paths that should be recomputed
96 // - The Flow Paths with modified Flow Entries
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -080097 // - The Flow Paths that we should check if installed in all switches
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -080098 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -080099 private Map<Long, FlowPath> shouldRecomputeFlowPaths =
100 new HashMap<Long, FlowPath>();
101 private Map<Long, FlowPath> modifiedFlowPaths =
102 new HashMap<Long, FlowPath>();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800103 private Map<Long, FlowPath> checkIfInstalledFlowPaths =
104 new HashMap<Long, FlowPath>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800105
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700106 /**
107 * Constructor for a given Flow Manager and Datagrid Service.
108 *
109 * @param flowManager the Flow Manager to use.
110 * @param datagridService the Datagrid Service to use.
111 */
Pavlin Radoslavov9a859022013-10-30 10:08:24 -0700112 FlowEventHandler(FlowManager flowManager,
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800113 IDatagridService datagridService) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700114 this.flowManager = flowManager;
115 this.datagridService = datagridService;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700116 this.topology = new Topology();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700117 }
118
119 /**
Pavlin Radoslavoved0f4a82013-11-04 16:38:36 -0800120 * Get the network topology.
121 *
122 * @return the network topology.
123 */
124 protected Topology getTopology() { return this.topology; }
125
126 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800127 * Startup processing.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700128 */
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800129 private void startup() {
Pavlin Radoslavov8252fee2014-01-07 17:24:29 -0800130 this.dbHandler = new GraphDBOperation("");
131
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700132 //
133 // Obtain the initial Topology state
134 //
135 Collection<TopologyElement> topologyElements =
136 datagridService.getAllTopologyElements();
137 for (TopologyElement topologyElement : topologyElements) {
138 EventEntry<TopologyElement> eventEntry =
139 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
140 topologyEvents.add(eventEntry);
141 }
142 //
143 // Obtain the initial Flow Path state
144 //
145 Collection<FlowPath> flowPaths = datagridService.getAllFlows();
146 for (FlowPath flowPath : flowPaths) {
147 EventEntry<FlowPath> eventEntry =
148 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
149 flowPathEvents.add(eventEntry);
150 }
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700151 //
152 // Obtain the initial FlowEntry state
153 //
154 Collection<FlowEntry> flowEntries = datagridService.getAllFlowEntries();
155 for (FlowEntry flowEntry : flowEntries) {
156 EventEntry<FlowEntry> eventEntry =
157 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
158 flowEntryEvents.add(eventEntry);
159 }
160
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800161 //
162 // Obtain the initial FlowId state
163 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800164 Collection<Pair<FlowId, Dpid>> flowIds =
165 datagridService.getAllFlowIds();
166 for (Pair<FlowId, Dpid> pair : flowIds) {
167 EventEntry<Pair<FlowId, Dpid>> eventEntry =
168 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800169 flowIdEvents.add(eventEntry);
170 }
171
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800172 //
173 // Obtain the initial FlowEntryId state
174 //
175 Collection<Pair<FlowEntryId, Dpid>> flowEntryIds =
176 datagridService.getAllFlowEntryIds();
177 for (Pair<FlowEntryId, Dpid> pair : flowEntryIds) {
178 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
179 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, pair);
180 flowEntryIdEvents.add(eventEntry);
181 }
182
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800183 // Process the initial events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800184 synchronized (allFlowPaths) {
185 processEvents();
186 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800187 }
188
189 /**
190 * Run the thread.
191 */
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800192 @Override
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800193 public void run() {
Yuta HIGUCHI61509a42013-12-17 10:41:04 -0800194 this.setName("FlowEventHandler " + this.getId());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800195 startup();
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700196
197 //
198 // The main loop
199 //
200 Collection<EventEntry<?>> collection = new LinkedList<EventEntry<?>>();
201 try {
202 while (true) {
203 EventEntry<?> eventEntry = networkEvents.take();
204 collection.add(eventEntry);
205 networkEvents.drainTo(collection);
206
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700207 //
208 // Demultiplex all events:
209 // - EventEntry<TopologyElement>
210 // - EventEntry<FlowPath>
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700211 // - EventEntry<FlowEntry>
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800212 // - EventEntry<Pair<FlowId, Dpid>>
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800213 // - EventEntry<Pair<FlowEntryId, Dpid>>
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700214 //
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700215 for (EventEntry<?> event : collection) {
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800216 // Topology event
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700217 if (event.eventData() instanceof TopologyElement) {
218 EventEntry<TopologyElement> topologyEventEntry =
219 (EventEntry<TopologyElement>)event;
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800220
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700221 topologyEvents.add(topologyEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800222 continue;
223 }
224
225 // FlowPath event
226 if (event.eventData() instanceof FlowPath) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700227 EventEntry<FlowPath> flowPathEventEntry =
228 (EventEntry<FlowPath>)event;
229 flowPathEvents.add(flowPathEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800230 continue;
231 }
232
233 // FlowEntry event
234 if (event.eventData() instanceof FlowEntry) {
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700235 EventEntry<FlowEntry> flowEntryEventEntry =
236 (EventEntry<FlowEntry>)event;
237 flowEntryEvents.add(flowEntryEventEntry);
Pavlin Radoslavovc8038a82013-12-02 17:43:20 -0800238 continue;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700239 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800240
241 // FlowId event
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800242 if (event.eventData() instanceof Pair) {
243 EventEntry<Pair<FlowId, Dpid>> flowIdEventEntry =
244 (EventEntry<Pair<FlowId, Dpid>>)event;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800245 flowIdEvents.add(flowIdEventEntry);
246 continue;
247 }
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800248
249 // Switch Dpid event
250 if (event.eventData() instanceof Dpid) {
251 EventEntry<Dpid> switchDpidEventEntry =
252 (EventEntry<Dpid>)event;
253 switchDpidEvents.add(switchDpidEventEntry);
254 continue;
255 }
256
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800257 // FlowEntryId event
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800258 // TODO: Fix the code below if we need again to handle
259 // the FlowEntryId events
260 /*
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -0800261 if (event.eventData() instanceof Pair) {
262 EventEntry<Pair<FlowEntryId, Dpid>> flowEntryIdEventEntry =
263 (EventEntry<Pair<FlowEntryId, Dpid>>)event;
264 flowEntryIdEvents.add(flowEntryIdEventEntry);
265 continue;
266 }
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800267 */
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700268 }
269 collection.clear();
Pavlin Radoslavoved4c7a92013-10-26 21:36:21 -0700270
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700271 // Process the events (if any)
Pavlin Radoslavov53219802013-12-06 11:02:04 -0800272 synchronized (allFlowPaths) {
273 processEvents();
274 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700275 }
276 } catch (Exception exception) {
277 log.debug("Exception processing Network Events: ", exception);
278 }
279 }
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800280
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700281 /**
282 * Process the events (if any)
283 */
284 private void processEvents() {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800285 Collection<FlowEntry> modifiedFlowEntries;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700286
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800287 if (enableOnrc2014MeasurementsFlows) {
288
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800289 if (topologyEvents.isEmpty() && flowIdEvents.isEmpty() &&
290 switchDpidEvents.isEmpty()) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800291 return; // Nothing to do
292 }
293
294 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
295
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800296 // Process the Switch Dpid events
297 processSwitchDpidEvents();
298
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800299 // Process the Flow ID events
300 processFlowIdEvents(mySwitches);
301
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800302 // Fetch the topology
303 processTopologyEvents();
304
305 // Recompute all affected Flow Paths and keep only the modified
306 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
307 if (recomputeFlowPath(flowPath))
308 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
309 }
310
311 // Assign the Flow Entry ID as needed
312 for (FlowPath flowPath : modifiedFlowPaths.values()) {
313 for (FlowEntry flowEntry : flowPath.flowEntries()) {
314 if (! flowEntry.isValidFlowEntryId()) {
315 long id = flowManager.getNextFlowEntryId();
316 flowEntry.setFlowEntryId(new FlowEntryId(id));
317 }
318 }
319 }
320
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800321 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800322 // Push the modified state to the database
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800323 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800324 flowManager.writeModifiedFlowPathsToDatabase(modifiedFlowPaths.values());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800325
326 // Cleanup
327 topologyEvents.clear();
328 flowIdEvents.clear();
329 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800330 // NOTE: Keep a cache with my Flow Paths
331 // allFlowPaths.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800332 shouldRecomputeFlowPaths.clear();
333 modifiedFlowPaths.clear();
334
335 return;
336 }
337
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700338 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800339 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700340 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700341 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700342
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800343 processFlowPathEvents();
344 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800345 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800346 processFlowEntryEvents();
347
348 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800349 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800350 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800351 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800352 }
353
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800354 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800355 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800356
357 // Assign missing Flow Entry IDs
358 assignFlowEntryId(modifiedFlowEntries);
359
360 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800361 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800362 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800363 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
364 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800365
366 //
367 // Remove Flow Entries that were deleted
368 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800369 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800370 flowPath.dataPath().removeDeletedFlowEntries();
371
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800372 //
373 // Check if Flow Paths have been installed into all switches,
374 // and generate the appropriate events.
375 //
376 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
377
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800378 // Cleanup
379 topologyEvents.clear();
380 flowPathEvents.clear();
381 flowEntryEvents.clear();
382 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800383 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800384 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800385 checkIfInstalledFlowPaths.clear();
386 }
387
388 /**
389 * Check if Flow Paths have been installed into all switches,
390 * and generate the appropriate events.
391 *
392 * @param flowPaths the flowPaths to process.
393 */
394 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
395 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
396
397 Kryo kryo = kryoFactory.newKryo();
398
399 for (FlowPath flowPath : flowPaths) {
400 boolean isInstalled = true;
401
402 //
403 // Check whether all Flow Entries have been installed
404 //
405 for (FlowEntry flowEntry : flowPath.flowEntries()) {
406 if (flowEntry.flowEntrySwitchState() !=
407 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
408 isInstalled = false;
409 break;
410 }
411 }
412
413 if (isInstalled) {
414 // Create a copy and add it to the list
415 FlowPath copyFlowPath = kryo.copy(flowPath);
416 installedFlowPaths.add(copyFlowPath);
417 }
418 }
419 kryoFactory.deleteKryo(kryo);
420
421 // Generate an event for the installed Flow Path.
422 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800423 }
424
425 /**
426 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800427 *
428 * @param modifiedFlowPaths the Flow Paths to process.
429 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800430 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800431 private Collection<FlowEntry> extractModifiedFlowEntries(
432 Collection<FlowPath> modifiedFlowPaths) {
433 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800434
435 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800436 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800437 for (FlowEntry flowEntry : flowPath.flowEntries()) {
438 if (flowEntry.flowEntrySwitchState() ==
439 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800440 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800441 }
442 }
443 }
444 return modifiedFlowEntries;
445 }
446
447 /**
448 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800449 *
450 * @param modifiedFlowEnries the collection of Flow Entries that need
451 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800452 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800453 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800454 if (modifiedFlowEntries.isEmpty())
455 return;
456
457 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
458
459 //
460 // Assign the Flow Entry ID only for Flow Entries for my switches
461 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800462 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800463 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
464 if (mySwitch == null)
465 continue;
466 if (! flowEntry.isValidFlowEntryId()) {
467 long id = flowManager.getNextFlowEntryId();
468 flowEntry.setFlowEntryId(new FlowEntryId(id));
469 }
470 }
471 }
472
473 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800474 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800475 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800476 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800477 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800478 private void fixFlowFromDatabase(FlowPath flowPath) {
479 //
480 // TODO: Bug workaround / fix :
481 // method FlowDatabaseOperation.extractFlowEntry() doesn't
482 // fetch the inPort and outPort, hence we assign them here.
483 //
484 // Assign the inPort and outPort for the Flow Entries
485 for (FlowEntry flowEntry : flowPath.flowEntries()) {
486 // Set the inPort
487 do {
488 if (flowEntry.inPort() != null)
489 break;
490 if (flowEntry.flowEntryMatch() == null)
491 break;
492 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
493 flowEntry.setInPort(inPort);
494 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800495
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800496 // Set the outPort
497 do {
498 if (flowEntry.outPort() != null)
499 break;
500 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
501 if (fa.actionOutput() != null) {
502 Port outPort = new Port(fa.actionOutput().port().value());
503 flowEntry.setOutPort(outPort);
504 break;
505 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800506 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800507 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800508 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800509 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800510
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800511 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800512 * Process the Switch Dpid events.
513 */
514 private void processSwitchDpidEvents() {
515 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
516 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
517
518 //
519 // Process all Switch Dpid events and update the appropriate state
520 //
521 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
522 Dpid dpid = eventEntry.eventData();
523
524 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
525
526 // Compute the final set of added and removed switches
527 switch (eventEntry.eventType()) {
528 case ENTRY_ADD:
529 addedSwitches.put(dpid.value(), dpid);
530 removedSwitches.remove(dpid.value());
531 break;
532 case ENTRY_REMOVE:
533 addedSwitches.remove(dpid.value());
534 removedSwitches.put(dpid.value(), dpid);
535 break;
536 }
537 }
538
539 //
540 // Remove the Flows from the local cache if the removed
541 // switch is the Source Switch.
542 //
543 // TODO: This search can be expensive for a large number of flows
544 // and should be optmized.
545 //
546 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
547 for (Dpid switchDpid : removedSwitches.values()) {
548 for (FlowPath flowPath : allFlowPaths.values()) {
549 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
550 if (srcDpid.value() == switchDpid.value())
551 deleteFlowIds.add(flowPath.flowId());
552 }
553 }
554 //
555 // Remove the Flows from the local cache
556 //
557 for (FlowId flowId : deleteFlowIds)
558 allFlowPaths.remove(flowId.value());
559
560 // Get the Flows for the added switches
561 Collection<FlowPath> flowPaths =
562 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
563 addedSwitches.values());
564 for (FlowPath flowPath : flowPaths) {
565 allFlowPaths.put(flowPath.flowId().value(), flowPath);
566 }
567 }
568
569 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800570 * Process the Flow ID events.
571 *
572 * @param mySwitches the collection of my switches.
573 */
574 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800575 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
576
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800577 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800578 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800579 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800580 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
581 Pair<FlowId, Dpid> pair = eventEntry.eventData();
582 FlowId flowId = pair.first;
583 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800584
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800585 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
586 flowId, dpid);
587
588 //
589 // Ignore Flows if the Source Switch is not controlled by this
590 // instance.
591 //
592 if (mySwitches.get(dpid.value()) == null)
593 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800594
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800595 switch (eventEntry.eventType()) {
596 case ENTRY_ADD: {
597 //
598 // Add a new Flow Path
599 //
600 if (allFlowPaths.get(flowId.value()) != null) {
601 //
602 // TODO: What to do if the Flow Path already exists?
603 // Fow now, we just re-add it.
604 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800605 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800606 shouldFetchMyFlowIds.add(flowId);
607
608 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800609 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800610
611 case ENTRY_REMOVE: {
612 //
613 // Remove an existing Flow Path.
614 //
615 // Find the Flow Path, and mark the Flow and its Flow Entries
616 // for deletion.
617 //
618 FlowPath existingFlowPath =
619 allFlowPaths.get(flowId.value());
620 if (existingFlowPath == null)
621 continue; // Nothing to do
622
623 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
624 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
625 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
626 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
627 }
628
629 // Remove the Flow Path from the internal state
630 Long key = existingFlowPath.flowId().value();
631 allFlowPaths.remove(key);
632 shouldRecomputeFlowPaths.remove(key);
633 modifiedFlowPaths.put(key, existingFlowPath);
634
635 break;
636 }
637 }
638 }
639
640 // Get my Flows
641 Collection<FlowPath> myFlows =
642 FlowDatabaseOperation.getFlows(dbHandler, shouldFetchMyFlowIds);
643
644 for (FlowPath flowPath : myFlows) {
645 fixFlowFromDatabase(flowPath);
646
647 switch (flowPath.flowPathType()) {
648 case FP_TYPE_SHORTEST_PATH:
649 //
650 // Reset the Data Path, in case it was set already, because
651 // we are going to recompute it anyway.
652 //
653 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800654 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
655 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800656 break;
657 case FP_TYPE_EXPLICIT_PATH:
658 //
659 // Mark all Flow Entries for installation in the switches.
660 //
661 for (FlowEntry flowEntry : flowPath.flowEntries()) {
662 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
663 }
664 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
665 break;
666 case FP_TYPE_UNKNOWN:
667 log.error("FlowPath event with unknown type");
668 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800669 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800670 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800671 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800672 }
673
674 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800675 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800676 *
677 * @param mySwitches the collection of my switches.
678 * @return a collection of modified Flow Entries this instance needs
679 * to push to its own switches.
680 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800681 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800682 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
683
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800684 //
685 // Process all Flow ID events and update the appropriate state
686 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800687 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
688 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
689 FlowEntryId flowEntryId = pair.first;
690 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800691
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800692 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
693 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800694
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800695 if (mySwitches.get(dpid.value()) == null)
696 continue;
697
698 // Fetch the Flow Entry
699 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
700 flowEntryId);
701 if (flowEntry == null) {
702 log.debug("Flow Entry ID {} : Flow Entry not found!",
703 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800704 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800705 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800706 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800707 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800708
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800709 return modifiedFlowEntries;
710 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800711
712 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800713 * Process the Flow Path events.
714 */
715 private void processFlowPathEvents() {
716 //
717 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700718 //
719 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
720 FlowPath flowPath = eventEntry.eventData();
721
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800722 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800723
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700724 switch (eventEntry.eventType()) {
725 case ENTRY_ADD: {
726 //
727 // Add a new Flow Path
728 //
729 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
730 //
731 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800732 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700733 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700734 }
735
736 switch (flowPath.flowPathType()) {
737 case FP_TYPE_SHORTEST_PATH:
738 //
739 // Reset the Data Path, in case it was set already, because
740 // we are going to recompute it anyway.
741 //
742 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800743 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
744 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700745 break;
746 case FP_TYPE_EXPLICIT_PATH:
747 //
748 // Mark all Flow Entries for installation in the switches.
749 //
750 for (FlowEntry flowEntry : flowPath.flowEntries()) {
751 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
752 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800753 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700754 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800755 case FP_TYPE_UNKNOWN:
756 log.error("FlowPath event with unknown type");
757 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700758 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800759 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700760
761 break;
762 }
763
764 case ENTRY_REMOVE: {
765 //
766 // Remove an existing Flow Path.
767 //
768 // Find the Flow Path, and mark the Flow and its Flow Entries
769 // for deletion.
770 //
771 FlowPath existingFlowPath =
772 allFlowPaths.get(flowPath.flowId().value());
773 if (existingFlowPath == null)
774 continue; // Nothing to do
775
776 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
777 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
778 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
779 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
780 }
781
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800782 // Remove the Flow Path from the internal state
783 Long key = existingFlowPath.flowId().value();
784 allFlowPaths.remove(key);
785 shouldRecomputeFlowPaths.remove(key);
786 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700787
788 break;
789 }
790 }
791 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800792 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700793
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800794 /**
795 * Process the Topology events.
796 */
797 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800798 boolean isTopologyModified = false;
799
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800800 if (enableOnrc2014MeasurementsTopology) {
801 if (topologyEvents.isEmpty())
802 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800803
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800804 // TODO: Code for debugging purpose only
805 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
806 TopologyElement topologyElement = eventEntry.eventData();
807 log.debug("Topology Event: {} {}", eventEntry.eventType(),
808 topologyElement.toString());
809 }
810
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800811 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800812 topology.readFromDatabase(dbHandler);
813 log.debug("[AFTER] {}", topology.toString());
814 shouldRecomputeFlowPaths.putAll(allFlowPaths);
815 return;
816 }
817
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700818 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800819 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700820 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800821 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
822 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800823
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800824 log.debug("Topology Event: {} {}", eventEntry.eventType(),
825 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800826
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800827 switch (eventEntry.eventType()) {
828 case ENTRY_ADD:
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800829 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800830 break;
831 case ENTRY_REMOVE:
Naoki Shiota9f6fc212014-01-09 21:38:08 -0800832 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800833 break;
834 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700835 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700836 if (isTopologyModified) {
837 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800838 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700839 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800840 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700841
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800842 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800843 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800844 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800845 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800846 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800847 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800848
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700849 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800850 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700851 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800852 if (! unmatchedFlowEntryAdd.isEmpty()) {
853 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
854 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800855 // log.debug("Processing Unmatched Flow Entry: {}",
856 // flowEntry.toString());
857
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800858 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800859 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800860 remainingUpdates.put(flowEntry.flowEntryId().value(),
861 flowEntry);
862 continue;
863 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800864 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
865 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800866 remainingUpdates.put(flowEntry.flowEntryId().value(),
867 flowEntry);
868 continue;
869 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800870 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
871 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
872 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700873 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800874 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700875 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800876 }
877
878 /**
879 * Process the Flow Entry events.
880 */
881 private void processFlowEntryEvents() {
882 FlowPath flowPath;
883 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700884
885 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800886 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700887 //
888 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
889 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800890
891 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800892 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800893
894 if ((! flowEntry.isValidFlowId()) ||
895 (! flowEntry.isValidFlowEntryId())) {
896 continue;
897 }
898
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700899 switch (eventEntry.eventType()) {
900 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800901 flowPath = allFlowPaths.get(flowEntry.flowId().value());
902 if (flowPath == null) {
903 // Flow Path not found: keep the entry for later matching
904 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
905 flowEntry);
906 break;
907 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800908 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
909 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800910 // Flow Entry not found: keep the entry for later matching
911 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
912 flowEntry);
913 break;
914 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800915 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
916 // Add the updated Flow Path to the list of updated paths
917 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
918 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700919 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800920
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700921 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800922 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
923 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800924 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800925 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800926
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800927 flowPath = allFlowPaths.get(flowEntry.flowId().value());
928 if (flowPath == null) {
929 // Flow Path not found: ignore the update
930 break;
931 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800932 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
933 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800934 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800935 break;
936 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800937 if (updateFlowEntryRemove(flowPath, localFlowEntry,
938 flowEntry)) {
939 // Add the updated Flow Path to the list of updated paths
940 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
941 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700942 break;
943 }
944 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700945 }
946
947 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800948 * Find a Flow Entry that should be updated because of an external
949 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700950 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800951 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800952 * @param newFlowEntry the FlowEntry with the new state.
953 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700954 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800955 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
956 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700957 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800958 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700959 //
960 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800961 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800962 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700963 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800964 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700965
966 //
967 // Local Flow Entry match found
968 //
969 if (localFlowEntry.isValidFlowEntryId()) {
970 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800971 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700972 //
973 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800974 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700975 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800976 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700977 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700978 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800979 return localFlowEntry;
980 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700981
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800982 return null; // Entry not found
983 }
984
985 /**
986 * Update a Flow Entry because of an external ENTRY_ADD event.
987 *
988 * @param flowPath the FlowPath for the Flow Entry to update.
989 * @param localFlowEntry the local Flow Entry to update.
990 * @param newFlowEntry the FlowEntry with the new state.
991 * @return true if the local Flow Entry was updated, otherwise false.
992 */
993 private boolean updateFlowEntryAdd(FlowPath flowPath,
994 FlowEntry localFlowEntry,
995 FlowEntry newFlowEntry) {
996 boolean updated = false;
997
998 if (localFlowEntry.flowEntryUserState() ==
999 FlowEntryUserState.FE_USER_DELETE) {
1000 // Don't add-back a Flow Entry that is already deleted
1001 return false;
1002 }
1003
1004 if (! localFlowEntry.isValidFlowEntryId()) {
1005 // Update the Flow Entry ID
1006 FlowEntryId flowEntryId =
1007 new FlowEntryId(newFlowEntry.flowEntryId().value());
1008 localFlowEntry.setFlowEntryId(flowEntryId);
1009 updated = true;
1010 }
1011
1012 //
1013 // Update the local Flow Entry, and keep state to check
1014 // if the Flow Path has been installed.
1015 //
1016 if (localFlowEntry.flowEntryUserState() !=
1017 newFlowEntry.flowEntryUserState()) {
1018 localFlowEntry.setFlowEntryUserState(
1019 newFlowEntry.flowEntryUserState());
1020 updated = true;
1021 }
1022 if (localFlowEntry.flowEntrySwitchState() !=
1023 newFlowEntry.flowEntrySwitchState()) {
1024 localFlowEntry.setFlowEntrySwitchState(
1025 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001026 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001027 updated = true;
1028 }
1029
1030 return updated;
1031 }
1032
1033 /**
1034 * Find a Flow Entry that should be updated because of an external
1035 * ENTRY_REMOVE event.
1036 *
1037 * @param flowPath the FlowPath for the Flow Entry to update.
1038 * @param newFlowEntry the FlowEntry with the new state.
1039 * @return the Flow Entry that should be updated if found, otherwise null.
1040 */
1041 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1042 FlowEntry newFlowEntry) {
1043 //
1044 // Iterate over all Flow Entries and find a match based on
1045 // the Flow Entry ID.
1046 //
1047 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1048 if (! localFlowEntry.isValidFlowEntryId())
1049 continue;
1050 if (localFlowEntry.flowEntryId().value() !=
1051 newFlowEntry.flowEntryId().value()) {
1052 continue;
1053 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001054 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001055 }
1056
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001057 return null; // Entry not found
1058 }
1059
1060 /**
1061 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1062 *
1063 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001064 * @param localFlowEntry the local Flow Entry to update.
1065 * @param newFlowEntry the FlowEntry with the new state.
1066 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001067 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001068 private boolean updateFlowEntryRemove(FlowPath flowPath,
1069 FlowEntry localFlowEntry,
1070 FlowEntry newFlowEntry) {
1071 boolean updated = false;
1072
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001073 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001074 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001075 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001076 if (localFlowEntry.flowEntryUserState() !=
1077 newFlowEntry.flowEntryUserState()) {
1078 localFlowEntry.setFlowEntryUserState(
1079 newFlowEntry.flowEntryUserState());
1080 updated = true;
1081 }
1082 if (localFlowEntry.flowEntrySwitchState() !=
1083 newFlowEntry.flowEntrySwitchState()) {
1084 localFlowEntry.setFlowEntrySwitchState(
1085 newFlowEntry.flowEntrySwitchState());
1086 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001087 }
1088
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001089 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001090 }
1091
1092 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001093 * Recompute a Flow Path.
1094 *
1095 * @param flowPath the Flow Path to recompute.
1096 * @return true if the recomputed Flow Path has changed, otherwise false.
1097 */
1098 private boolean recomputeFlowPath(FlowPath flowPath) {
1099 boolean hasChanged = false;
1100
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001101 if (enableOnrc2014MeasurementsFlows) {
1102 // Cleanup the deleted Flow Entries from the earlier iteration
1103 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001104
1105 //
1106 // TODO: Fake it that the Flow Entries have been already pushed
1107 // into the switches, so we don't push them again.
1108 //
1109 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1110 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1111 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001112 }
1113
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001114 //
1115 // Test whether the Flow Path needs to be recomputed
1116 //
1117 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001118 case FP_TYPE_UNKNOWN:
1119 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001120 case FP_TYPE_SHORTEST_PATH:
1121 break;
1122 case FP_TYPE_EXPLICIT_PATH:
1123 return false; // An explicit path never changes
1124 }
1125
1126 DataPath oldDataPath = flowPath.dataPath();
1127
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001128 // Compute the new path
Naoki Shiota9f6fc212014-01-09 21:38:08 -08001129 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001130 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001131
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001132 if (newDataPath == null) {
1133 // We need the DataPath to compare the paths
1134 newDataPath = new DataPath();
1135 }
1136 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1137
1138 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001139 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001140 //
1141 if (oldDataPath.flowEntries().size() !=
1142 newDataPath.flowEntries().size()) {
1143 hasChanged = true;
1144 } else {
1145 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1146 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1147 while (oldIter.hasNext() && newIter.hasNext()) {
1148 FlowEntry oldFlowEntry = oldIter.next();
1149 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001150 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1151 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001152 hasChanged = true;
1153 break;
1154 }
1155 }
1156 }
1157 if (! hasChanged)
1158 return hasChanged;
1159
1160 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001161 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001162 // - If a Flow Entry for a switch is in the old data path, but not
1163 // in the new data path, then mark it for deletion.
1164 // - If a Flow Entry for a switch is in the new data path, but not
1165 // in the old data path, then mark it for addition.
1166 // - If a Flow Entry for a switch is in both the old and the new
1167 // data path, but it has changed, e.g., the incoming and/or outgoing
1168 // port(s), then mark the old Flow Entry for deletion, and mark
1169 // the new Flow Entry for addition.
1170 // - If a Flow Entry for a switch is in both the old and the new
1171 // data path, and it hasn't changed, then just keep it.
1172 //
1173 // NOTE: We use the Switch DPID of each entry to match the entries
1174 //
1175 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1176 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1177 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1178 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1179
1180 // Prepare maps with the Flow Entries, so they are fast to lookup
1181 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1182 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1183 for (FlowEntry flowEntry : newDataPath.flowEntries())
1184 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1185
1186 //
1187 // Find the old Flow Entries that should be deleted
1188 //
1189 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1190 FlowEntry newFlowEntry =
1191 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1192 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001193 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001194 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1195 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1196 deletedFlowEntries.add(oldFlowEntry);
1197 }
1198 }
1199
1200 //
1201 // Find the new Flow Entries that should be added or updated
1202 //
1203 int idx = 0;
1204 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1205 FlowEntry oldFlowEntry =
1206 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1207
1208 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001209 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1210 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001211 //
1212 // Both Flow Entries are same
1213 //
1214 finalFlowEntries.add(oldFlowEntry);
1215 idx++;
1216 continue;
1217 }
1218
1219 if (oldFlowEntry != null) {
1220 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001221 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001222 //
1223 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1224 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1225 deletedFlowEntries.add(oldFlowEntry);
1226 }
1227
1228 //
1229 // Add the new Flow Entry
1230 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001231 //
1232 // NOTE: Assign only the Flow ID.
1233 // The Flow Entry ID is assigned later only for the Flow Entries
1234 // this instance is responsible for.
1235 //
1236 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001237
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001238 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001239 // Copy the Flow timeouts
1240 //
1241 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1242 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1243
1244 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001245 // Allocate the FlowEntryMatch by copying the default one
1246 // from the FlowPath (if set).
1247 //
1248 FlowEntryMatch flowEntryMatch = null;
1249 if (flowPath.flowEntryMatch() != null)
1250 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1251 else
1252 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001253 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001254
1255 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001256 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1257
1258 //
1259 // Set the actions:
1260 // If the first Flow Entry, copy the Flow Path actions to it.
1261 //
1262 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1263 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1264 FlowEntryActions flowActions =
1265 new FlowEntryActions(flowPath.flowEntryActions());
1266 for (FlowEntryAction action : flowActions.actions())
1267 flowEntryActions.addAction(action);
1268 }
1269 idx++;
1270
1271 //
1272 // Add the outgoing port output action
1273 //
1274 FlowEntryAction flowEntryAction = new FlowEntryAction();
1275 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1276 flowEntryActions.addAction(flowEntryAction);
1277
1278 //
1279 // Set the state of the new Flow Entry
1280 //
1281 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1282 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1283 finalFlowEntries.add(newFlowEntry);
1284 }
1285
1286 //
1287 // Replace the old Flow Entries with the new Flow Entries.
1288 // Note that the Flow Entries that will be deleted are added at
1289 // the end.
1290 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001291 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001292 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1293
1294 return hasChanged;
1295 }
1296
1297 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001298 * Receive a notification that a Flow is added.
1299 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001300 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001301 */
1302 @Override
1303 public void notificationRecvFlowAdded(FlowPath flowPath) {
1304 EventEntry<FlowPath> eventEntry =
1305 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1306 networkEvents.add(eventEntry);
1307 }
1308
1309 /**
1310 * Receive a notification that a Flow is removed.
1311 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001312 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001313 */
1314 @Override
1315 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1316 EventEntry<FlowPath> eventEntry =
1317 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1318 networkEvents.add(eventEntry);
1319 }
1320
1321 /**
1322 * Receive a notification that a Flow is updated.
1323 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001324 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001325 */
1326 @Override
1327 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1328 // NOTE: The ADD and UPDATE events are processed in same way
1329 EventEntry<FlowPath> eventEntry =
1330 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1331 networkEvents.add(eventEntry);
1332 }
1333
1334 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001335 * Receive a notification that a FlowEntry is added.
1336 *
1337 * @param flowEntry the FlowEntry that is added.
1338 */
1339 @Override
1340 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001341 if (enableOnrc2014MeasurementsFlows) {
1342 Collection entries = new ArrayList();
1343 entries.add(flowEntry);
1344 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1345 return;
1346 }
1347
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001348 EventEntry<FlowEntry> eventEntry =
1349 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1350 networkEvents.add(eventEntry);
1351 }
1352
1353 /**
1354 * Receive a notification that a FlowEntry is removed.
1355 *
1356 * @param flowEntry the FlowEntry that is removed.
1357 */
1358 @Override
1359 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001360 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001361 //
1362 // NOTE: Must update the state to DELETE, because
1363 // the notification contains the original state.
1364 //
1365 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1366
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001367 Collection entries = new ArrayList();
1368 entries.add(flowEntry);
1369 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1370 return;
1371 }
1372
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001373 EventEntry<FlowEntry> eventEntry =
1374 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1375 networkEvents.add(eventEntry);
1376 }
1377
1378 /**
1379 * Receive a notification that a FlowEntry is updated.
1380 *
1381 * @param flowEntry the FlowEntry that is updated.
1382 */
1383 @Override
1384 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001385 if (enableOnrc2014MeasurementsFlows) {
1386 Collection entries = new ArrayList();
1387 entries.add(flowEntry);
1388 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1389 return;
1390 }
1391
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001392 // NOTE: The ADD and UPDATE events are processed in same way
1393 EventEntry<FlowEntry> eventEntry =
1394 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1395 networkEvents.add(eventEntry);
1396 }
1397
1398 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001399 * Receive a notification that a FlowId is added.
1400 *
1401 * @param flowId the FlowId that is added.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001402 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001403 */
1404 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001405 public void notificationRecvFlowIdAdded(FlowId flowId, Dpid dpid) {
1406 Pair flowIdPair = new Pair(flowId, dpid);
1407
1408 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1409 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001410 networkEvents.add(eventEntry);
1411 }
1412
1413 /**
1414 * Receive a notification that a FlowId is removed.
1415 *
1416 * @param flowId the FlowId that is removed.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001417 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001418 */
1419 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001420 public void notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1421 Pair flowIdPair = new Pair(flowId, dpid);
1422
1423 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1424 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001425 networkEvents.add(eventEntry);
1426 }
1427
1428 /**
1429 * Receive a notification that a FlowId is updated.
1430 *
1431 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001432 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001433 */
1434 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001435 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1436 Pair flowIdPair = new Pair(flowId, dpid);
1437
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001438 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001439 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1440 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001441 networkEvents.add(eventEntry);
1442 }
1443
1444 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001445 * Receive a notification that a FlowEntryId is added.
1446 *
1447 * @param flowEntryId the FlowEntryId that is added.
1448 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1449 */
1450 @Override
1451 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1452 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001453 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1454
1455 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1456 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001457 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001458 }
1459
1460 /**
1461 * Receive a notification that a FlowEntryId is removed.
1462 *
1463 * @param flowEntryId the FlowEntryId that is removed.
1464 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1465 */
1466 @Override
1467 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1468 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001469 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1470
1471 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1472 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001473 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001474 }
1475
1476 /**
1477 * Receive a notification that a FlowEntryId is updated.
1478 *
1479 * @param flowEntryId the FlowEntryId that is updated.
1480 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1481 */
1482 @Override
1483 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1484 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001485 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1486
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001487 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001488 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1489 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001490 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001491 }
1492
1493 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001494 * Receive a notification that a Topology Element is added.
1495 *
1496 * @param topologyElement the Topology Element that is added.
1497 */
1498 @Override
1499 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1500 EventEntry<TopologyElement> eventEntry =
1501 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1502 networkEvents.add(eventEntry);
1503 }
1504
1505 /**
1506 * Receive a notification that a Topology Element is removed.
1507 *
1508 * @param topologyElement the Topology Element that is removed.
1509 */
1510 @Override
1511 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1512 EventEntry<TopologyElement> eventEntry =
1513 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1514 networkEvents.add(eventEntry);
1515 }
1516
1517 /**
1518 * Receive a notification that a Topology Element is updated.
1519 *
1520 * @param topologyElement the Topology Element that is updated.
1521 */
1522 @Override
1523 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1524 // NOTE: The ADD and UPDATE events are processed in same way
1525 EventEntry<TopologyElement> eventEntry =
1526 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1527 networkEvents.add(eventEntry);
1528 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001529
1530 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001531 * Receive a notification that a switch is added to this instance.
1532 *
1533 * @param sw the switch that is added.
1534 */
1535 @Override
1536 public void addedSwitch(IOFSwitch sw) {
1537 Dpid dpid = new Dpid(sw.getId());
1538 EventEntry<Dpid> eventEntry =
1539 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1540 networkEvents.add(eventEntry);
1541 }
1542
1543 /**
1544 * Receive a notification that a switch is removed from this instance.
1545 *
1546 * @param sw the switch that is removed.
1547 */
1548 @Override
1549 public void removedSwitch(IOFSwitch sw) {
1550 Dpid dpid = new Dpid(sw.getId());
1551 EventEntry<Dpid> eventEntry =
1552 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1553 networkEvents.add(eventEntry);
1554 }
1555
1556 /**
1557 * Receive a notification that the ports on a switch have changed.
1558 */
1559 @Override
1560 public void switchPortChanged(Long switchId) {
1561 // Nothing to do
1562 }
1563
1564 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001565 * Get a sorted copy of all Flow Paths.
1566 *
1567 * @return a sorted copy of all Flow Paths.
1568 */
1569 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1570 SortedMap<Long, FlowPath> sortedFlowPaths =
1571 new TreeMap<Long, FlowPath>();
1572
1573 //
1574 // TODO: For now we use serialization/deserialization to create
1575 // a copy of each Flow Path. In the future, we should use proper
1576 // copy constructors.
1577 //
1578 Kryo kryo = kryoFactory.newKryo();
1579 synchronized (allFlowPaths) {
1580 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1581 FlowPath origFlowPath = entry.getValue();
1582 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1583 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1584 }
1585 }
1586 kryoFactory.deleteKryo(kryo);
1587
1588 return sortedFlowPaths;
1589 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001590}