blob: de372ef3c386b8bbd596e0ad0e0252eaabd1913e [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();
Pavlin Radoslavov2d6e5f12014-01-10 16:34:05 -0800329 switchDpidEvents.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800330 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800331 // NOTE: Keep a cache with my Flow Paths
332 // allFlowPaths.clear();
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800333 shouldRecomputeFlowPaths.clear();
334 modifiedFlowPaths.clear();
335
336 return;
337 }
338
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700339 if (topologyEvents.isEmpty() && flowPathEvents.isEmpty() &&
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800340 flowEntryEvents.isEmpty()) {
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700341 return; // Nothing to do
Pavlin Radoslavovb7506842013-10-29 17:46:54 -0700342 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -0700343
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800344 processFlowPathEvents();
345 processTopologyEvents();
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800346 processUnmatchedFlowEntryAdd();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800347 processFlowEntryEvents();
348
349 // Recompute all affected Flow Paths and keep only the modified
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800350 for (FlowPath flowPath : shouldRecomputeFlowPaths.values()) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800351 if (recomputeFlowPath(flowPath))
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800352 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800353 }
354
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800355 // Extract the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800356 modifiedFlowEntries = extractModifiedFlowEntries(modifiedFlowPaths.values());
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800357
358 // Assign missing Flow Entry IDs
359 assignFlowEntryId(modifiedFlowEntries);
360
361 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800362 // Push the modified state to the Flow Manager
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800363 //
Pavlin Radoslavova0c16362013-12-04 13:18:08 -0800364 flowManager.pushModifiedFlowState(modifiedFlowPaths.values(),
365 modifiedFlowEntries);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800366
367 //
368 // Remove Flow Entries that were deleted
369 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800370 for (FlowPath flowPath : modifiedFlowPaths.values())
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800371 flowPath.dataPath().removeDeletedFlowEntries();
372
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800373 //
374 // Check if Flow Paths have been installed into all switches,
375 // and generate the appropriate events.
376 //
377 checkInstalledFlowPaths(checkIfInstalledFlowPaths.values());
378
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800379 // Cleanup
380 topologyEvents.clear();
381 flowPathEvents.clear();
382 flowEntryEvents.clear();
383 //
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800384 shouldRecomputeFlowPaths.clear();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800385 modifiedFlowPaths.clear();
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800386 checkIfInstalledFlowPaths.clear();
387 }
388
389 /**
390 * Check if Flow Paths have been installed into all switches,
391 * and generate the appropriate events.
392 *
393 * @param flowPaths the flowPaths to process.
394 */
395 private void checkInstalledFlowPaths(Collection<FlowPath> flowPaths) {
396 List<FlowPath> installedFlowPaths = new LinkedList<FlowPath>();
397
398 Kryo kryo = kryoFactory.newKryo();
399
400 for (FlowPath flowPath : flowPaths) {
401 boolean isInstalled = true;
402
403 //
404 // Check whether all Flow Entries have been installed
405 //
406 for (FlowEntry flowEntry : flowPath.flowEntries()) {
407 if (flowEntry.flowEntrySwitchState() !=
408 FlowEntrySwitchState.FE_SWITCH_UPDATED) {
409 isInstalled = false;
410 break;
411 }
412 }
413
414 if (isInstalled) {
415 // Create a copy and add it to the list
416 FlowPath copyFlowPath = kryo.copy(flowPath);
417 installedFlowPaths.add(copyFlowPath);
418 }
419 }
420 kryoFactory.deleteKryo(kryo);
421
422 // Generate an event for the installed Flow Path.
423 flowManager.notificationFlowPathsInstalled(installedFlowPaths);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800424 }
425
426 /**
427 * Extract the modified Flow Entries.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800428 *
429 * @param modifiedFlowPaths the Flow Paths to process.
430 * @return a collection with the modified Flow Entries.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800431 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800432 private Collection<FlowEntry> extractModifiedFlowEntries(
433 Collection<FlowPath> modifiedFlowPaths) {
434 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800435
436 // Extract only the modified Flow Entries
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800437 for (FlowPath flowPath : modifiedFlowPaths) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800438 for (FlowEntry flowEntry : flowPath.flowEntries()) {
439 if (flowEntry.flowEntrySwitchState() ==
440 FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED) {
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800441 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800442 }
443 }
444 }
445 return modifiedFlowEntries;
446 }
447
448 /**
449 * Assign the Flow Entry ID as needed.
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800450 *
451 * @param modifiedFlowEnries the collection of Flow Entries that need
452 * Flow Entry ID assigned.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800453 */
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800454 private void assignFlowEntryId(Collection<FlowEntry> modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800455 if (modifiedFlowEntries.isEmpty())
456 return;
457
458 Map<Long, IOFSwitch> mySwitches = flowManager.getMySwitches();
459
460 //
461 // Assign the Flow Entry ID only for Flow Entries for my switches
462 //
Pavlin Radoslavovafc4aa92013-12-04 12:44:23 -0800463 for (FlowEntry flowEntry : modifiedFlowEntries) {
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800464 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
465 if (mySwitch == null)
466 continue;
467 if (! flowEntry.isValidFlowEntryId()) {
468 long id = flowManager.getNextFlowEntryId();
469 flowEntry.setFlowEntryId(new FlowEntryId(id));
470 }
471 }
472 }
473
474 /**
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800475 * Fix a flow fetched from the database.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800476 *
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800477 * @param flowPath the Flow to fix.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800478 */
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800479 private void fixFlowFromDatabase(FlowPath flowPath) {
480 //
481 // TODO: Bug workaround / fix :
482 // method FlowDatabaseOperation.extractFlowEntry() doesn't
483 // fetch the inPort and outPort, hence we assign them here.
484 //
485 // Assign the inPort and outPort for the Flow Entries
486 for (FlowEntry flowEntry : flowPath.flowEntries()) {
487 // Set the inPort
488 do {
489 if (flowEntry.inPort() != null)
490 break;
491 if (flowEntry.flowEntryMatch() == null)
492 break;
493 Port inPort = new Port(flowEntry.flowEntryMatch().inPort().value());
494 flowEntry.setInPort(inPort);
495 } while (false);
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800496
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800497 // Set the outPort
498 do {
499 if (flowEntry.outPort() != null)
500 break;
501 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
502 if (fa.actionOutput() != null) {
503 Port outPort = new Port(fa.actionOutput().port().value());
504 flowEntry.setOutPort(outPort);
505 break;
506 }
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800507 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800508 } while (false);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800509 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800510 }
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800511
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800512 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800513 * Process the Switch Dpid events.
514 */
515 private void processSwitchDpidEvents() {
516 Map<Long, Dpid> addedSwitches = new HashMap<Long, Dpid>();
517 Map<Long, Dpid> removedSwitches = new HashMap<Long, Dpid>();
518
519 //
520 // Process all Switch Dpid events and update the appropriate state
521 //
522 for (EventEntry<Dpid> eventEntry : switchDpidEvents) {
523 Dpid dpid = eventEntry.eventData();
524
525 log.debug("SwitchDpid Event: {} {}", eventEntry.eventType(), dpid);
526
527 // Compute the final set of added and removed switches
528 switch (eventEntry.eventType()) {
529 case ENTRY_ADD:
530 addedSwitches.put(dpid.value(), dpid);
531 removedSwitches.remove(dpid.value());
532 break;
533 case ENTRY_REMOVE:
534 addedSwitches.remove(dpid.value());
535 removedSwitches.put(dpid.value(), dpid);
536 break;
537 }
538 }
539
540 //
541 // Remove the Flows from the local cache if the removed
542 // switch is the Source Switch.
543 //
544 // TODO: This search can be expensive for a large number of flows
545 // and should be optmized.
546 //
547 List<FlowId> deleteFlowIds = new LinkedList<FlowId>();
548 for (Dpid switchDpid : removedSwitches.values()) {
549 for (FlowPath flowPath : allFlowPaths.values()) {
550 Dpid srcDpid = flowPath.dataPath().srcPort().dpid();
551 if (srcDpid.value() == switchDpid.value())
552 deleteFlowIds.add(flowPath.flowId());
553 }
554 }
555 //
556 // Remove the Flows from the local cache
557 //
558 for (FlowId flowId : deleteFlowIds)
559 allFlowPaths.remove(flowId.value());
560
561 // Get the Flows for the added switches
562 Collection<FlowPath> flowPaths =
563 ParallelFlowDatabaseOperation.getFlowsForSwitches(dbHandler,
564 addedSwitches.values());
565 for (FlowPath flowPath : flowPaths) {
566 allFlowPaths.put(flowPath.flowId().value(), flowPath);
567 }
568 }
569
570 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800571 * Process the Flow ID events.
572 *
573 * @param mySwitches the collection of my switches.
574 */
575 private void processFlowIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800576 List<FlowId> shouldFetchMyFlowIds = new LinkedList<FlowId>();
577
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800578 //
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800579 // Process all Flow Id events and update the appropriate state
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800580 //
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800581 for (EventEntry<Pair<FlowId, Dpid>> eventEntry : flowIdEvents) {
582 Pair<FlowId, Dpid> pair = eventEntry.eventData();
583 FlowId flowId = pair.first;
584 Dpid dpid = pair.second;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800585
Pavlin Radoslavov2194d112014-01-10 13:36:00 -0800586 log.debug("Flow ID Event: {} {} {}", eventEntry.eventType(),
587 flowId, dpid);
588
589 //
590 // Ignore Flows if the Source Switch is not controlled by this
591 // instance.
592 //
593 if (mySwitches.get(dpid.value()) == null)
594 continue;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800595
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800596 switch (eventEntry.eventType()) {
597 case ENTRY_ADD: {
598 //
599 // Add a new Flow Path
600 //
601 if (allFlowPaths.get(flowId.value()) != null) {
602 //
603 // TODO: What to do if the Flow Path already exists?
604 // Fow now, we just re-add it.
605 //
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800606 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800607 shouldFetchMyFlowIds.add(flowId);
608
609 break;
Pavlin Radoslavov3a7cc902014-01-09 02:32:08 -0800610 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800611
612 case ENTRY_REMOVE: {
613 //
614 // Remove an existing Flow Path.
615 //
616 // Find the Flow Path, and mark the Flow and its Flow Entries
617 // for deletion.
618 //
619 FlowPath existingFlowPath =
620 allFlowPaths.get(flowId.value());
621 if (existingFlowPath == null)
622 continue; // Nothing to do
623
624 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
625 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
626 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
627 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
628 }
629
630 // Remove the Flow Path from the internal state
631 Long key = existingFlowPath.flowId().value();
632 allFlowPaths.remove(key);
633 shouldRecomputeFlowPaths.remove(key);
634 modifiedFlowPaths.put(key, existingFlowPath);
635
636 break;
637 }
638 }
639 }
640
641 // Get my Flows
642 Collection<FlowPath> myFlows =
Pavlin Radoslavov6602b6a2014-01-10 16:43:29 -0800643 ParallelFlowDatabaseOperation.getFlows(dbHandler,
644 shouldFetchMyFlowIds);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800645
646 for (FlowPath flowPath : myFlows) {
647 fixFlowFromDatabase(flowPath);
648
649 switch (flowPath.flowPathType()) {
650 case FP_TYPE_SHORTEST_PATH:
651 //
652 // Reset the Data Path, in case it was set already, because
653 // we are going to recompute it anyway.
654 //
655 flowPath.flowEntries().clear();
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800656 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
657 flowPath);
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800658 break;
659 case FP_TYPE_EXPLICIT_PATH:
660 //
661 // Mark all Flow Entries for installation in the switches.
662 //
663 for (FlowEntry flowEntry : flowPath.flowEntries()) {
664 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
665 }
666 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
667 break;
668 case FP_TYPE_UNKNOWN:
669 log.error("FlowPath event with unknown type");
670 break;
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800671 }
Pavlin Radoslavov417398f2014-01-10 13:04:33 -0800672 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovdb1f91c2014-01-08 16:04:17 -0800673 }
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800674 }
675
676 /**
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800677 * Process the Flow Entry ID events.
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800678 *
679 * @param mySwitches the collection of my switches.
680 * @return a collection of modified Flow Entries this instance needs
681 * to push to its own switches.
682 */
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800683 private Collection<FlowEntry> processFlowEntryIdEvents(Map<Long, IOFSwitch> mySwitches) {
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800684 List<FlowEntry> modifiedFlowEntries = new LinkedList<FlowEntry>();
685
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800686 //
687 // Process all Flow ID events and update the appropriate state
688 //
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800689 for (EventEntry<Pair<FlowEntryId, Dpid>> eventEntry : flowEntryIdEvents) {
690 Pair<FlowEntryId, Dpid> pair = eventEntry.eventData();
691 FlowEntryId flowEntryId = pair.first;
692 Dpid dpid = pair.second;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800693
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800694 log.debug("Flow Entry ID Event: {} {} {}", eventEntry.eventType(),
695 flowEntryId, dpid);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800696
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800697 if (mySwitches.get(dpid.value()) == null)
698 continue;
699
700 // Fetch the Flow Entry
701 FlowEntry flowEntry = FlowDatabaseOperation.getFlowEntry(dbHandler,
702 flowEntryId);
703 if (flowEntry == null) {
704 log.debug("Flow Entry ID {} : Flow Entry not found!",
705 flowEntryId);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800706 continue;
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800707 }
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800708 modifiedFlowEntries.add(flowEntry);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800709 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800710
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800711 return modifiedFlowEntries;
712 }
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -0800713
714 /**
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800715 * Process the Flow Path events.
716 */
717 private void processFlowPathEvents() {
718 //
719 // Process all Flow Path events and update the appropriate state
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700720 //
721 for (EventEntry<FlowPath> eventEntry : flowPathEvents) {
722 FlowPath flowPath = eventEntry.eventData();
723
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800724 log.debug("Flow Event: {} {}", eventEntry.eventType(), flowPath);
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800725
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700726 switch (eventEntry.eventType()) {
727 case ENTRY_ADD: {
728 //
729 // Add a new Flow Path
730 //
731 if (allFlowPaths.get(flowPath.flowId().value()) != null) {
732 //
733 // TODO: What to do if the Flow Path already exists?
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800734 // Fow now, we just re-add it.
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700735 //
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700736 }
737
738 switch (flowPath.flowPathType()) {
739 case FP_TYPE_SHORTEST_PATH:
740 //
741 // Reset the Data Path, in case it was set already, because
742 // we are going to recompute it anyway.
743 //
744 flowPath.flowEntries().clear();
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800745 shouldRecomputeFlowPaths.put(flowPath.flowId().value(),
746 flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700747 break;
748 case FP_TYPE_EXPLICIT_PATH:
749 //
750 // Mark all Flow Entries for installation in the switches.
751 //
752 for (FlowEntry flowEntry : flowPath.flowEntries()) {
753 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
754 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800755 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700756 break;
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800757 case FP_TYPE_UNKNOWN:
758 log.error("FlowPath event with unknown type");
759 break;
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700760 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800761 allFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700762
763 break;
764 }
765
766 case ENTRY_REMOVE: {
767 //
768 // Remove an existing Flow Path.
769 //
770 // Find the Flow Path, and mark the Flow and its Flow Entries
771 // for deletion.
772 //
773 FlowPath existingFlowPath =
774 allFlowPaths.get(flowPath.flowId().value());
775 if (existingFlowPath == null)
776 continue; // Nothing to do
777
778 existingFlowPath.setFlowPathUserState(FlowPathUserState.FP_USER_DELETE);
779 for (FlowEntry flowEntry : existingFlowPath.flowEntries()) {
780 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
781 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
782 }
783
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800784 // Remove the Flow Path from the internal state
785 Long key = existingFlowPath.flowId().value();
786 allFlowPaths.remove(key);
787 shouldRecomputeFlowPaths.remove(key);
788 modifiedFlowPaths.put(key, existingFlowPath);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700789
790 break;
791 }
792 }
793 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800794 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700795
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800796 /**
797 * Process the Topology events.
798 */
799 private void processTopologyEvents() {
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800800 boolean isTopologyModified = false;
801
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800802 if (enableOnrc2014MeasurementsTopology) {
803 if (topologyEvents.isEmpty())
804 return;
Pavlin Radoslavov52119fa2014-01-09 13:37:52 -0800805
Pavlin Radoslavov2a8b9de2014-01-09 15:58:32 -0800806 // TODO: Code for debugging purpose only
807 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
808 TopologyElement topologyElement = eventEntry.eventData();
809 log.debug("Topology Event: {} {}", eventEntry.eventType(),
810 topologyElement.toString());
811 }
812
Pavlin Radoslavov1b454902014-01-09 16:28:27 -0800813 log.debug("[BEFORE] {}", topology.toString());
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800814 topology.readFromDatabase(dbHandler);
815 log.debug("[AFTER] {}", topology.toString());
816 shouldRecomputeFlowPaths.putAll(allFlowPaths);
817 return;
818 }
819
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700820 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800821 // Process all Topology events and update the appropriate state
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700822 //
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800823 for (EventEntry<TopologyElement> eventEntry : topologyEvents) {
824 TopologyElement topologyElement = eventEntry.eventData();
Naoki Shiota0abe38d2014-01-07 15:31:22 -0800825
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800826 log.debug("Topology Event: {} {}", eventEntry.eventType(),
827 topologyElement.toString());
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -0800828
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800829 switch (eventEntry.eventType()) {
830 case ENTRY_ADD:
Pavlin Radoslavovcc757162014-01-10 16:26:38 -0800831 isTopologyModified |= topology.addTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800832 break;
833 case ENTRY_REMOVE:
Naoki Shiota9f6fc212014-01-09 21:38:08 -0800834 isTopologyModified |= topology.removeTopologyElement(topologyElement);
Pavlin Radoslavov80bc3cf2014-01-08 11:17:30 -0800835 break;
836 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700837 }
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700838 if (isTopologyModified) {
839 // TODO: For now, if the topology changes, we recompute all Flows
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800840 shouldRecomputeFlowPaths.putAll(allFlowPaths);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -0700841 }
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800842 }
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700843
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800844 /**
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800845 * Process previously received Flow Entries with unmatched Flow Paths.
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800846 */
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800847 private void processUnmatchedFlowEntryAdd() {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800848 FlowPath flowPath;
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800849 FlowEntry localFlowEntry;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800850
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700851 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800852 // Update Flow Entries with previously unmatched Flow Entry updates
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700853 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800854 if (! unmatchedFlowEntryAdd.isEmpty()) {
855 Map<Long, FlowEntry> remainingUpdates = new HashMap<Long, FlowEntry>();
856 for (FlowEntry flowEntry : unmatchedFlowEntryAdd.values()) {
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800857 // log.debug("Processing Unmatched Flow Entry: {}",
858 // flowEntry.toString());
859
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800860 flowPath = allFlowPaths.get(flowEntry.flowId().value());
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800861 if (flowPath == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800862 remainingUpdates.put(flowEntry.flowEntryId().value(),
863 flowEntry);
864 continue;
865 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800866 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
867 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800868 remainingUpdates.put(flowEntry.flowEntryId().value(),
869 flowEntry);
870 continue;
871 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800872 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
873 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
874 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700875 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800876 unmatchedFlowEntryAdd = remainingUpdates;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700877 }
Pavlin Radoslavov9bb40552013-12-18 21:08:30 -0800878 }
879
880 /**
881 * Process the Flow Entry events.
882 */
883 private void processFlowEntryEvents() {
884 FlowPath flowPath;
885 FlowEntry localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700886
887 //
Pavlin Radoslavov9f33edb2013-11-06 18:24:37 -0800888 // Process all Flow Entry events and update the appropriate state
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700889 //
890 for (EventEntry<FlowEntry> eventEntry : flowEntryEvents) {
891 FlowEntry flowEntry = eventEntry.eventData();
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800892
893 log.debug("Flow Entry Event: {} {}", eventEntry.eventType(),
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800894 flowEntry);
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800895
896 if ((! flowEntry.isValidFlowId()) ||
897 (! flowEntry.isValidFlowEntryId())) {
898 continue;
899 }
900
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700901 switch (eventEntry.eventType()) {
902 case ENTRY_ADD:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800903 flowPath = allFlowPaths.get(flowEntry.flowId().value());
904 if (flowPath == null) {
905 // Flow Path not found: keep the entry for later matching
906 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
907 flowEntry);
908 break;
909 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800910 localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
911 if (localFlowEntry == null) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800912 // Flow Entry not found: keep the entry for later matching
913 unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
914 flowEntry);
915 break;
916 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800917 if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
918 // Add the updated Flow Path to the list of updated paths
919 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
920 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700921 break;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800922
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700923 case ENTRY_REMOVE:
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800924 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
925 if (unmatchedFlowEntryAdd.remove(flowEntry.flowEntryId().value()) != null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800926 continue; // Removed previously unmatched entry
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800927 }
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800928
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800929 flowPath = allFlowPaths.get(flowEntry.flowId().value());
930 if (flowPath == null) {
931 // Flow Path not found: ignore the update
932 break;
933 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800934 localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
935 if (localFlowEntry == null) {
Pavlin Radoslavov2fca8d12013-12-04 09:39:06 -0800936 // Flow Entry not found: ignore it
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800937 break;
938 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800939 if (updateFlowEntryRemove(flowPath, localFlowEntry,
940 flowEntry)) {
941 // Add the updated Flow Path to the list of updated paths
942 modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
943 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700944 break;
945 }
946 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700947 }
948
949 /**
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800950 * Find a Flow Entry that should be updated because of an external
951 * ENTRY_ADD event.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700952 *
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800953 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800954 * @param newFlowEntry the FlowEntry with the new state.
955 * @return the Flow Entry that should be updated if found, otherwise null.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700956 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800957 private FlowEntry findFlowEntryAdd(FlowPath flowPath,
958 FlowEntry newFlowEntry) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700959 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800960 // Iterate over all Flow Entries and find a match.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700961 //
962 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800963 if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800964 newFlowEntry)) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700965 continue;
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800966 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700967
968 //
969 // Local Flow Entry match found
970 //
971 if (localFlowEntry.isValidFlowEntryId()) {
972 if (localFlowEntry.flowEntryId().value() !=
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800973 newFlowEntry.flowEntryId().value()) {
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700974 //
975 // Find a local Flow Entry, but the Flow Entry ID doesn't
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800976 // match. Keep looking.
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700977 //
Pavlin Radoslavov63117172013-11-07 02:18:37 -0800978 continue;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700979 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700980 }
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800981 return localFlowEntry;
982 }
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -0700983
Pavlin Radoslavov237fde72013-12-17 22:21:06 -0800984 return null; // Entry not found
985 }
986
987 /**
988 * Update a Flow Entry because of an external ENTRY_ADD event.
989 *
990 * @param flowPath the FlowPath for the Flow Entry to update.
991 * @param localFlowEntry the local Flow Entry to update.
992 * @param newFlowEntry the FlowEntry with the new state.
993 * @return true if the local Flow Entry was updated, otherwise false.
994 */
995 private boolean updateFlowEntryAdd(FlowPath flowPath,
996 FlowEntry localFlowEntry,
997 FlowEntry newFlowEntry) {
998 boolean updated = false;
999
1000 if (localFlowEntry.flowEntryUserState() ==
1001 FlowEntryUserState.FE_USER_DELETE) {
1002 // Don't add-back a Flow Entry that is already deleted
1003 return false;
1004 }
1005
1006 if (! localFlowEntry.isValidFlowEntryId()) {
1007 // Update the Flow Entry ID
1008 FlowEntryId flowEntryId =
1009 new FlowEntryId(newFlowEntry.flowEntryId().value());
1010 localFlowEntry.setFlowEntryId(flowEntryId);
1011 updated = true;
1012 }
1013
1014 //
1015 // Update the local Flow Entry, and keep state to check
1016 // if the Flow Path has been installed.
1017 //
1018 if (localFlowEntry.flowEntryUserState() !=
1019 newFlowEntry.flowEntryUserState()) {
1020 localFlowEntry.setFlowEntryUserState(
1021 newFlowEntry.flowEntryUserState());
1022 updated = true;
1023 }
1024 if (localFlowEntry.flowEntrySwitchState() !=
1025 newFlowEntry.flowEntrySwitchState()) {
1026 localFlowEntry.setFlowEntrySwitchState(
1027 newFlowEntry.flowEntrySwitchState());
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -08001028 checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001029 updated = true;
1030 }
1031
1032 return updated;
1033 }
1034
1035 /**
1036 * Find a Flow Entry that should be updated because of an external
1037 * ENTRY_REMOVE event.
1038 *
1039 * @param flowPath the FlowPath for the Flow Entry to update.
1040 * @param newFlowEntry the FlowEntry with the new state.
1041 * @return the Flow Entry that should be updated if found, otherwise null.
1042 */
1043 private FlowEntry findFlowEntryRemove(FlowPath flowPath,
1044 FlowEntry newFlowEntry) {
1045 //
1046 // Iterate over all Flow Entries and find a match based on
1047 // the Flow Entry ID.
1048 //
1049 for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
1050 if (! localFlowEntry.isValidFlowEntryId())
1051 continue;
1052 if (localFlowEntry.flowEntryId().value() !=
1053 newFlowEntry.flowEntryId().value()) {
1054 continue;
1055 }
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001056 return localFlowEntry;
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001057 }
1058
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001059 return null; // Entry not found
1060 }
1061
1062 /**
1063 * Update a Flow Entry because of an external ENTRY_REMOVE event.
1064 *
1065 * @param flowPath the FlowPath for the Flow Entry to update.
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001066 * @param localFlowEntry the local Flow Entry to update.
1067 * @param newFlowEntry the FlowEntry with the new state.
1068 * @return true if the local Flow Entry was updated, otherwise false.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001069 */
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001070 private boolean updateFlowEntryRemove(FlowPath flowPath,
1071 FlowEntry localFlowEntry,
1072 FlowEntry newFlowEntry) {
1073 boolean updated = false;
1074
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001075 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001076 // Update the local Flow Entry.
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001077 //
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001078 if (localFlowEntry.flowEntryUserState() !=
1079 newFlowEntry.flowEntryUserState()) {
1080 localFlowEntry.setFlowEntryUserState(
1081 newFlowEntry.flowEntryUserState());
1082 updated = true;
1083 }
1084 if (localFlowEntry.flowEntrySwitchState() !=
1085 newFlowEntry.flowEntrySwitchState()) {
1086 localFlowEntry.setFlowEntrySwitchState(
1087 newFlowEntry.flowEntrySwitchState());
1088 updated = true;
Pavlin Radoslavov63117172013-11-07 02:18:37 -08001089 }
1090
Pavlin Radoslavov237fde72013-12-17 22:21:06 -08001091 return updated;
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001092 }
1093
1094 /**
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001095 * Recompute a Flow Path.
1096 *
1097 * @param flowPath the Flow Path to recompute.
1098 * @return true if the recomputed Flow Path has changed, otherwise false.
1099 */
1100 private boolean recomputeFlowPath(FlowPath flowPath) {
1101 boolean hasChanged = false;
1102
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001103 if (enableOnrc2014MeasurementsFlows) {
1104 // Cleanup the deleted Flow Entries from the earlier iteration
1105 flowPath.dataPath().removeDeletedFlowEntries();
Pavlin Radoslavov737aa522014-01-09 15:35:00 -08001106
1107 //
1108 // TODO: Fake it that the Flow Entries have been already pushed
1109 // into the switches, so we don't push them again.
1110 //
1111 for (FlowEntry flowEntry : flowPath.flowEntries()) {
1112 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
1113 }
Pavlin Radoslavov7bf837a2014-01-09 14:22:05 -08001114 }
1115
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001116 //
1117 // Test whether the Flow Path needs to be recomputed
1118 //
1119 switch (flowPath.flowPathType()) {
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -07001120 case FP_TYPE_UNKNOWN:
1121 return false; // Can't recompute on Unknown FlowType
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001122 case FP_TYPE_SHORTEST_PATH:
1123 break;
1124 case FP_TYPE_EXPLICIT_PATH:
1125 return false; // An explicit path never changes
1126 }
1127
1128 DataPath oldDataPath = flowPath.dataPath();
1129
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001130 // Compute the new path
Naoki Shiota9f6fc212014-01-09 21:38:08 -08001131 DataPath newDataPath = TopologyManager.computeNetworkPath(topology,
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001132 flowPath);
Naoki Shiotaf74d5f32014-01-09 21:29:38 -08001133
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001134 if (newDataPath == null) {
1135 // We need the DataPath to compare the paths
1136 newDataPath = new DataPath();
1137 }
1138 newDataPath.applyFlowPathFlags(flowPath.flowPathFlags());
1139
1140 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001141 // Test whether the new path is same
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001142 //
1143 if (oldDataPath.flowEntries().size() !=
1144 newDataPath.flowEntries().size()) {
1145 hasChanged = true;
1146 } else {
1147 Iterator<FlowEntry> oldIter = oldDataPath.flowEntries().iterator();
1148 Iterator<FlowEntry> newIter = newDataPath.flowEntries().iterator();
1149 while (oldIter.hasNext() && newIter.hasNext()) {
1150 FlowEntry oldFlowEntry = oldIter.next();
1151 FlowEntry newFlowEntry = newIter.next();
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001152 if (! TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1153 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001154 hasChanged = true;
1155 break;
1156 }
1157 }
1158 }
1159 if (! hasChanged)
1160 return hasChanged;
1161
1162 //
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001163 // Merge the changes in the path:
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001164 // - If a Flow Entry for a switch is in the old data path, but not
1165 // in the new data path, then mark it for deletion.
1166 // - If a Flow Entry for a switch is in the new data path, but not
1167 // in the old data path, then mark it for addition.
1168 // - If a Flow Entry for a switch is in both the old and the new
1169 // data path, but it has changed, e.g., the incoming and/or outgoing
1170 // port(s), then mark the old Flow Entry for deletion, and mark
1171 // the new Flow Entry for addition.
1172 // - If a Flow Entry for a switch is in both the old and the new
1173 // data path, and it hasn't changed, then just keep it.
1174 //
1175 // NOTE: We use the Switch DPID of each entry to match the entries
1176 //
1177 Map<Long, FlowEntry> oldFlowEntriesMap = new HashMap<Long, FlowEntry>();
1178 Map<Long, FlowEntry> newFlowEntriesMap = new HashMap<Long, FlowEntry>();
1179 ArrayList<FlowEntry> finalFlowEntries = new ArrayList<FlowEntry>();
1180 List<FlowEntry> deletedFlowEntries = new LinkedList<FlowEntry>();
1181
1182 // Prepare maps with the Flow Entries, so they are fast to lookup
1183 for (FlowEntry flowEntry : oldDataPath.flowEntries())
1184 oldFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1185 for (FlowEntry flowEntry : newDataPath.flowEntries())
1186 newFlowEntriesMap.put(flowEntry.dpid().value(), flowEntry);
1187
1188 //
1189 // Find the old Flow Entries that should be deleted
1190 //
1191 for (FlowEntry oldFlowEntry : oldDataPath.flowEntries()) {
1192 FlowEntry newFlowEntry =
1193 newFlowEntriesMap.get(oldFlowEntry.dpid().value());
1194 if (newFlowEntry == null) {
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001195 // The old Flow Entry should be deleted: not on the path
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001196 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1197 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1198 deletedFlowEntries.add(oldFlowEntry);
1199 }
1200 }
1201
1202 //
1203 // Find the new Flow Entries that should be added or updated
1204 //
1205 int idx = 0;
1206 for (FlowEntry newFlowEntry : newDataPath.flowEntries()) {
1207 FlowEntry oldFlowEntry =
1208 oldFlowEntriesMap.get(newFlowEntry.dpid().value());
1209
1210 if ((oldFlowEntry != null) &&
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -07001211 TopologyManager.isSameFlowEntryDataPath(oldFlowEntry,
1212 newFlowEntry)) {
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001213 //
1214 // Both Flow Entries are same
1215 //
1216 finalFlowEntries.add(oldFlowEntry);
1217 idx++;
1218 continue;
1219 }
1220
1221 if (oldFlowEntry != null) {
1222 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001223 // The old Flow Entry should be deleted: path diverges
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001224 //
1225 oldFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1226 oldFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1227 deletedFlowEntries.add(oldFlowEntry);
1228 }
1229
1230 //
1231 // Add the new Flow Entry
1232 //
Pavlin Radoslavov1c24f222013-10-30 13:56:46 -07001233 //
1234 // NOTE: Assign only the Flow ID.
1235 // The Flow Entry ID is assigned later only for the Flow Entries
1236 // this instance is responsible for.
1237 //
1238 newFlowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001239
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001240 //
Pavlin Radoslavov6fde2172013-12-10 11:23:18 -08001241 // Copy the Flow timeouts
1242 //
1243 newFlowEntry.setIdleTimeout(flowPath.idleTimeout());
1244 newFlowEntry.setHardTimeout(flowPath.hardTimeout());
1245
1246 //
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001247 // Allocate the FlowEntryMatch by copying the default one
1248 // from the FlowPath (if set).
1249 //
1250 FlowEntryMatch flowEntryMatch = null;
1251 if (flowPath.flowEntryMatch() != null)
1252 flowEntryMatch = new FlowEntryMatch(flowPath.flowEntryMatch());
1253 else
1254 flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001255 newFlowEntry.setFlowEntryMatch(flowEntryMatch);
Pavlin Radoslavova4df9522013-12-03 11:03:04 -08001256
1257 // Set the incoming port matching
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001258 flowEntryMatch.enableInPort(newFlowEntry.inPort());
1259
1260 //
1261 // Set the actions:
1262 // If the first Flow Entry, copy the Flow Path actions to it.
1263 //
1264 FlowEntryActions flowEntryActions = newFlowEntry.flowEntryActions();
1265 if ((idx == 0) && (flowPath.flowEntryActions() != null)) {
1266 FlowEntryActions flowActions =
1267 new FlowEntryActions(flowPath.flowEntryActions());
1268 for (FlowEntryAction action : flowActions.actions())
1269 flowEntryActions.addAction(action);
1270 }
1271 idx++;
1272
1273 //
1274 // Add the outgoing port output action
1275 //
1276 FlowEntryAction flowEntryAction = new FlowEntryAction();
1277 flowEntryAction.setActionOutput(newFlowEntry.outPort());
1278 flowEntryActions.addAction(flowEntryAction);
1279
1280 //
1281 // Set the state of the new Flow Entry
1282 //
1283 newFlowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1284 newFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
1285 finalFlowEntries.add(newFlowEntry);
1286 }
1287
1288 //
1289 // Replace the old Flow Entries with the new Flow Entries.
1290 // Note that the Flow Entries that will be deleted are added at
1291 // the end.
1292 //
Pavlin Radoslavovfb94edc2013-11-04 16:29:40 -08001293 finalFlowEntries.addAll(deletedFlowEntries);
Pavlin Radoslavovfb06a9e2013-10-28 23:56:15 -07001294 flowPath.dataPath().setFlowEntries(finalFlowEntries);
1295
1296 return hasChanged;
1297 }
1298
1299 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001300 * Receive a notification that a Flow is added.
1301 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001302 * @param flowPath the Flow that is added.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001303 */
1304 @Override
1305 public void notificationRecvFlowAdded(FlowPath flowPath) {
1306 EventEntry<FlowPath> eventEntry =
1307 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1308 networkEvents.add(eventEntry);
1309 }
1310
1311 /**
1312 * Receive a notification that a Flow is removed.
1313 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001314 * @param flowPath the Flow that is removed.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001315 */
1316 @Override
1317 public void notificationRecvFlowRemoved(FlowPath flowPath) {
1318 EventEntry<FlowPath> eventEntry =
1319 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_REMOVE, flowPath);
1320 networkEvents.add(eventEntry);
1321 }
1322
1323 /**
1324 * Receive a notification that a Flow is updated.
1325 *
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001326 * @param flowPath the Flow that is updated.
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001327 */
1328 @Override
1329 public void notificationRecvFlowUpdated(FlowPath flowPath) {
1330 // NOTE: The ADD and UPDATE events are processed in same way
1331 EventEntry<FlowPath> eventEntry =
1332 new EventEntry<FlowPath>(EventEntry.Type.ENTRY_ADD, flowPath);
1333 networkEvents.add(eventEntry);
1334 }
1335
1336 /**
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001337 * Receive a notification that a FlowEntry is added.
1338 *
1339 * @param flowEntry the FlowEntry that is added.
1340 */
1341 @Override
1342 public void notificationRecvFlowEntryAdded(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001343 if (enableOnrc2014MeasurementsFlows) {
1344 Collection entries = new ArrayList();
1345 entries.add(flowEntry);
1346 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1347 return;
1348 }
1349
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001350 EventEntry<FlowEntry> eventEntry =
1351 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1352 networkEvents.add(eventEntry);
1353 }
1354
1355 /**
1356 * Receive a notification that a FlowEntry is removed.
1357 *
1358 * @param flowEntry the FlowEntry that is removed.
1359 */
1360 @Override
1361 public void notificationRecvFlowEntryRemoved(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001362 if (enableOnrc2014MeasurementsFlows) {
Pavlin Radoslavove4d2a432014-01-10 12:01:08 -08001363 //
1364 // NOTE: Must update the state to DELETE, because
1365 // the notification contains the original state.
1366 //
1367 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
1368
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001369 Collection entries = new ArrayList();
1370 entries.add(flowEntry);
1371 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1372 return;
1373 }
1374
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001375 EventEntry<FlowEntry> eventEntry =
1376 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_REMOVE, flowEntry);
1377 networkEvents.add(eventEntry);
1378 }
1379
1380 /**
1381 * Receive a notification that a FlowEntry is updated.
1382 *
1383 * @param flowEntry the FlowEntry that is updated.
1384 */
1385 @Override
1386 public void notificationRecvFlowEntryUpdated(FlowEntry flowEntry) {
Pavlin Radoslavov7847db72014-01-10 11:35:21 -08001387 if (enableOnrc2014MeasurementsFlows) {
1388 Collection entries = new ArrayList();
1389 entries.add(flowEntry);
1390 flowManager.pushModifiedFlowEntriesToSwitches(entries);
1391 return;
1392 }
1393
Pavlin Radoslavovb7506842013-10-29 17:46:54 -07001394 // NOTE: The ADD and UPDATE events are processed in same way
1395 EventEntry<FlowEntry> eventEntry =
1396 new EventEntry<FlowEntry>(EventEntry.Type.ENTRY_ADD, flowEntry);
1397 networkEvents.add(eventEntry);
1398 }
1399
1400 /**
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001401 * Receive a notification that a FlowId is added.
1402 *
1403 * @param flowId the FlowId that is added.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001404 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001405 */
1406 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001407 public void notificationRecvFlowIdAdded(FlowId flowId, Dpid dpid) {
1408 Pair flowIdPair = new Pair(flowId, dpid);
1409
1410 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1411 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001412 networkEvents.add(eventEntry);
1413 }
1414
1415 /**
1416 * Receive a notification that a FlowId is removed.
1417 *
1418 * @param flowId the FlowId that is removed.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001419 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001420 */
1421 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001422 public void notificationRecvFlowIdRemoved(FlowId flowId, Dpid dpid) {
1423 Pair flowIdPair = new Pair(flowId, dpid);
1424
1425 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1426 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001427 networkEvents.add(eventEntry);
1428 }
1429
1430 /**
1431 * Receive a notification that a FlowId is updated.
1432 *
1433 * @param flowId the FlowId that is updated.
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001434 * @param dpid the Source Switch Dpid for the corresponding Flow.
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001435 */
1436 @Override
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001437 public void notificationRecvFlowIdUpdated(FlowId flowId, Dpid dpid) {
1438 Pair flowIdPair = new Pair(flowId, dpid);
1439
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001440 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavov2194d112014-01-10 13:36:00 -08001441 EventEntry<Pair<FlowId, Dpid>> eventEntry =
1442 new EventEntry<Pair<FlowId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowIdPair);
Pavlin Radoslavov2004fa02014-01-07 14:46:42 -08001443 networkEvents.add(eventEntry);
1444 }
1445
1446 /**
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001447 * Receive a notification that a FlowEntryId is added.
1448 *
1449 * @param flowEntryId the FlowEntryId that is added.
1450 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1451 */
1452 @Override
1453 public void notificationRecvFlowEntryIdAdded(FlowEntryId flowEntryId,
1454 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001455 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1456
1457 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1458 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001459 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001460 }
1461
1462 /**
1463 * Receive a notification that a FlowEntryId is removed.
1464 *
1465 * @param flowEntryId the FlowEntryId that is removed.
1466 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1467 */
1468 @Override
1469 public void notificationRecvFlowEntryIdRemoved(FlowEntryId flowEntryId,
1470 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001471 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1472
1473 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1474 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_REMOVE, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001475 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001476 }
1477
1478 /**
1479 * Receive a notification that a FlowEntryId is updated.
1480 *
1481 * @param flowEntryId the FlowEntryId that is updated.
1482 * @param dpid the Switch Dpid for the corresponding Flow Entry.
1483 */
1484 @Override
1485 public void notificationRecvFlowEntryIdUpdated(FlowEntryId flowEntryId,
1486 Dpid dpid) {
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001487 Pair flowEntryIdPair = new Pair(flowEntryId, dpid);
1488
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001489 // NOTE: The ADD and UPDATE events are processed in same way
Pavlin Radoslavova9c0c3b2014-01-09 10:54:45 -08001490 EventEntry<Pair<FlowEntryId, Dpid>> eventEntry =
1491 new EventEntry<Pair<FlowEntryId, Dpid>>(EventEntry.Type.ENTRY_ADD, flowEntryIdPair);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001492 networkEvents.add(eventEntry);
Pavlin Radoslavov909da3c2014-01-09 04:04:33 -08001493 }
1494
1495 /**
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001496 * Receive a notification that a Topology Element is added.
1497 *
1498 * @param topologyElement the Topology Element that is added.
1499 */
1500 @Override
1501 public void notificationRecvTopologyElementAdded(TopologyElement topologyElement) {
1502 EventEntry<TopologyElement> eventEntry =
1503 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1504 networkEvents.add(eventEntry);
1505 }
1506
1507 /**
1508 * Receive a notification that a Topology Element is removed.
1509 *
1510 * @param topologyElement the Topology Element that is removed.
1511 */
1512 @Override
1513 public void notificationRecvTopologyElementRemoved(TopologyElement topologyElement) {
1514 EventEntry<TopologyElement> eventEntry =
1515 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_REMOVE, topologyElement);
1516 networkEvents.add(eventEntry);
1517 }
1518
1519 /**
1520 * Receive a notification that a Topology Element is updated.
1521 *
1522 * @param topologyElement the Topology Element that is updated.
1523 */
1524 @Override
1525 public void notificationRecvTopologyElementUpdated(TopologyElement topologyElement) {
1526 // NOTE: The ADD and UPDATE events are processed in same way
1527 EventEntry<TopologyElement> eventEntry =
1528 new EventEntry<TopologyElement>(EventEntry.Type.ENTRY_ADD, topologyElement);
1529 networkEvents.add(eventEntry);
1530 }
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001531
1532 /**
Pavlin Radoslavovcc757162014-01-10 16:26:38 -08001533 * Receive a notification that a switch is added to this instance.
1534 *
1535 * @param sw the switch that is added.
1536 */
1537 @Override
1538 public void addedSwitch(IOFSwitch sw) {
1539 Dpid dpid = new Dpid(sw.getId());
1540 EventEntry<Dpid> eventEntry =
1541 new EventEntry<Dpid>(EventEntry.Type.ENTRY_ADD, dpid);
1542 networkEvents.add(eventEntry);
1543 }
1544
1545 /**
1546 * Receive a notification that a switch is removed from this instance.
1547 *
1548 * @param sw the switch that is removed.
1549 */
1550 @Override
1551 public void removedSwitch(IOFSwitch sw) {
1552 Dpid dpid = new Dpid(sw.getId());
1553 EventEntry<Dpid> eventEntry =
1554 new EventEntry<Dpid>(EventEntry.Type.ENTRY_REMOVE, dpid);
1555 networkEvents.add(eventEntry);
1556 }
1557
1558 /**
1559 * Receive a notification that the ports on a switch have changed.
1560 */
1561 @Override
1562 public void switchPortChanged(Long switchId) {
1563 // Nothing to do
1564 }
1565
1566 /**
Pavlin Radoslavov53219802013-12-06 11:02:04 -08001567 * Get a sorted copy of all Flow Paths.
1568 *
1569 * @return a sorted copy of all Flow Paths.
1570 */
1571 synchronized SortedMap<Long, FlowPath> getAllFlowPathsCopy() {
1572 SortedMap<Long, FlowPath> sortedFlowPaths =
1573 new TreeMap<Long, FlowPath>();
1574
1575 //
1576 // TODO: For now we use serialization/deserialization to create
1577 // a copy of each Flow Path. In the future, we should use proper
1578 // copy constructors.
1579 //
1580 Kryo kryo = kryoFactory.newKryo();
1581 synchronized (allFlowPaths) {
1582 for (Map.Entry<Long, FlowPath> entry : allFlowPaths.entrySet()) {
1583 FlowPath origFlowPath = entry.getValue();
1584 FlowPath copyFlowPath = kryo.copy(origFlowPath);
1585 sortedFlowPaths.put(entry.getKey(), copyFlowPath);
1586 }
1587 }
1588 kryoFactory.deleteKryo(kryo);
1589
1590 return sortedFlowPaths;
1591 }
Pavlin Radoslavov6b79f2b2013-10-26 21:31:10 -07001592}